时过境迁,广告sdk相比以往稍有改变,不过大体思路都是一样的,最简单的就是去看开发文档,基本上不需要再自己另外单独分析。像国外的广告或者自己插入的广告就需要通过布局ID、联网日志、线程分析找到广告老巢了。
建议软件
1、MT管理器
比较简单,适合新手,不适合小白。可以去掉一些没有防护,或者防护比较弱的广告。
七猫免费小说so自带签名校验,校验大写签名SHA1,目标libcommon-encryption的
checkSignUseApplicationPackageManager
函数,相关代码如下:
ARM汇编:
.text:0000DD58 ; ---------------------------------------------------------------------------
.text:0000DD58
.text:0000DD58 loc_DD58 ; CODE XREF: checkSignUseApplicationPackageManager(_JNIEnv *)+458↑j
.text:0000DD58 MOVS R0, #0 ; 初始化
.text:0000DD5A MOV R1, R10
.text:0000DD5C STRB R0, [R6,R4] ; r0地址的数据写入r6+r4
.text:0000DD5E LDR.W R0, [R11] ; r11数据写入r0
.text:0000DD62 LDR R2, [R0,#0x5C]
.text:0000DD64 MOV R0, R11
.text:0000DD66 BLX R2 ; 调用r2函数
.text:0000DD68 LDR R1, =(a846bb6e12205a3 - 0xDD70) ; 这是保存在so的正确值
.text:0000DD6A MOV R0, R6 ; r6=s1,r6为读取到的实际值
.text:0000DD6C ADD R1, PC ; "846BB6E12205A3245D1E78C934EDA27EA02D5BD"...
.text:0000DD6E BLX strcmp ; r0、r1用于参数传递,传入到strcmp函数中
.text:0000DD72 MOV R4, R0 ; 函数返回值为r0,r0的值放入r4暂存
.text:0000DD74 MOV R0, R6 ; void *
.text:0000DD76 BLX j__ZdaPv ; operator delete[](void *)
.text:0000DD7A CMP R4, #0 ; 比较r4的值是否为0
.text:0000DD7C BEQ.W loc_DC2E ; 相等跳转指令
.text:0000DD80 LDR R1, =(aSignCheckSha1E - 0xDD86) ; "sign_check_sha1_error"
.text:0000DD82 ADD R1, PC ; 不等则运行到这里,报错
.text:0000DD84 B loc_DDD8
.text:0000DD86 ; ---------------------------------------------------------------------------
伪代码:
v60[2 * v57] = 0;
env->functions->DeleteLocalRef(env, v56);
v73 = strcmp(v60, "846BB6E12205A3245D1E78C934EDA27EA02D5BD5");
operator delete[](v60);
if ( v73 )
{
v74 = "sign_check_sha1_error";
LABEL_67:
throwException(env, v74);
return 0;
}
如果直接签名就安装的话,会无法连网。解决方法是用MT管理器的一键HOOK,或者把sha1改成自己的。如果修改so汇编,把ADD R1, PC改成MOV R1,R6即可。
除了签名校验,还有一个是包名校验。因为广告一般要读取包名的,如果包名不对会影响到广告投放。改包名能不能去广告,我还没试,有兴趣的可以试一下。
check_package_name_valid
函数是包名校验。
ARM汇编:
.text:0000D620
.text:0000D620 ; =============== S U B R O U T I N E =======================================
.text:0000D620
.text:0000D620 ; Attributes: bp-based frame
.text:0000D620
.text:0000D620 ; _DWORD check_package_name_valid(void)
.text:0000D620 EXPORT _Z24check_package_name_validv
.text:0000D620 _Z24check_package_name_validv ; CODE XREF: check_package_name_valid(void)+8↑j
.text:0000D620 ; DATA XREF: LOAD:000027B0↑o ...
.text:0000D620
.text:0000D620 var_14 = -0x14
.text:0000D620
.text:0000D620 ; __unwind {
.text:0000D620 PUSH {R4-R7,LR}
.text:0000D622 ADD R7, SP, #0xC
.text:0000D624 PUSH.W {R11}
.text:0000D628 SUB SP, SP, #0x108
.text:0000D62A LDR R0, =(__stack_chk_guard_ptr - 0xD630)
.text:0000D62C ADD R0, PC ; __stack_chk_guard_ptr
.text:0000D62E LDR R6, [R0] ; __stack_chk_guard
.text:0000D630 LDR R0, [R6]
.text:0000D632 STR R0, [SP,#0x118+var_14]
.text:0000D634 BLX getpid ; 获取进程pid
.text:0000D638 MOV R5, SP ;栈顶指针
.text:0000D63A MOV R4, R0
.text:0000D63C MOV R0, R5
.text:0000D63E MOV.W R1, #0x100
.text:0000D642 BLX __aeabi_memclr8
.text:0000D646 MOV R0, R4 ; int
.text:0000D648 MOV R1, R5 ; char *
.text:0000D64A BLX j__Z14getPackageNameiPc ; 使用/proc/%d/cmdline
.text:0000D64E CMP R0, #1
.text:0000D650 BLT loc_D660
.text:0000D652 LDR R1, =(aComKmxsReader - 0xD65C) ; "com.kmxs.reader"
.text:0000D654 MOV R0, SP ; s1
.text:0000D656 MOVS R2, #0x10 ; 对比16个字符串,最后一个是00,实际字符串个数为16-1
.text:0000D658 ADD R1, PC ; "com.kmxs.reader"
.text:0000D65A BLX memcmp
.text:0000D65E CBZ R0, loc_D664 ; 条件跳转指令
.text:0000D660
.text:0000D660 loc_D660 ; CODE XREF: check_package_name_valid(void)+30↑j
.text:0000D660 MOVS R0, #0 ; 输出结果为0,一般为假
.text:0000D662 B loc_D666
.text:0000D664 ; ---------------------------------------------------------------------------
.text:0000D664
.text:0000D664 loc_D664 ; CODE XREF: check_package_name_valid(void)+3E↑j
.text:0000D664 MOVS R0, #1 ; 输出结果为1,一般为真
.text:0000D666
.text:0000D666 loc_D666 ; CODE XREF: check_package_name_valid(void)+42↑j
.text:0000D666 LDR R1, [R6]
.text:0000D668 LDR R2, [SP,#0x118+var_14]
.text:0000D66A SUBS R1, R1, R2
.text:0000D66C ITTT EQ
.text:0000D66E ADDEQ SP, SP, #0x108
.text:0000D670 POPEQ.W {R11}
.text:0000D674 POPEQ {R4-R7,PC}
.text:0000D676 BLX __stack_chk_fail
.text:0000D676 ; End of function check_package_name_valid(void)
.text:0000D676
.text:0000D676 ; ---------------------------------------------------------------------------
.text:0000D67A ALIGN 4
.text:0000D67C off_D67C DCD __stack_chk_guard_ptr - 0xD630
.text:0000D67C ; DATA XREF: check_package_name_valid(void)+A↑r
.text:0000D680 off_D680 DCD aComKmxsReader - 0xD65C
.text:0000D680 ; DATA XREF: check_package_name_valid(void)+32↑r
.text:0000D680 ; } // starts at D620 ; "com.kmxs.reader"
伪代码:
bool check_package_name_valid(void) //类型为布尔
{
int v0; // r4
char v2[260]; // [sp+0h] [bp-118h] BYREF
v0 = getpid();
memset(v2, 0, 0x100u);
return getPackageName(v0, v2) >= 1 && !strcmp(v2, "com.kmxs.reader");
}
so反调试检测TracerPid一般也是和七猫小说一样用
/proc/%d/cmdline
,这是非常方便的。
C++举例:
#include
#include
#include
#include
void check(){
const int bufsize = 1024;
char filename[bufsize];
char line[bufsize];
char name[bufsize];
char nameline[bufsize];
int pid = getpid();
sprintf(filename, "/proc/%d/status", pid);
FILE *fd;
fd = fopen(filename, "r"); //“r”为读取,常见的dex校验要有这个
if (fd != nullptr)
while (fgets(line, bufsize, fd))
if (strstr(line, "TracerPid") != nullptr) { //被调试的时候不为0
int statue;
statue = atoi(&line[10]);
if (statue != 0) {
sprintf(name, "/proc/%d/cmdline", statue);
FILE *fdname;
fdname = fopen(name, "r");
if (fdname != nullptr)
while (fgets(nameline, bufsize, fdname))
if (strstr(nameline, "android_server") != nullptr) { //这是ida调试的文件
pthread_kill(pid, 9);
}
fclose(fdname);
}
}
fclose(fd);
}
1.png (215.79 KB, 下载次数: 0)
下载附件
2022-1-8 22:35 上传
可以利用AS编译成so查看arm汇编,必要时是可以patch汇编进去的。之前我出过一个教程是拷贝寄存器的字符串,实际上就是利用AS编译C++进行指针操作。
333.jpg (20.3 KB, 下载次数: 1)
下载附件
2022-1-8 22:45 上传
(为什么MD有一段汇编是鸭绿色的)
首先是新版穿山甲广告,看一下现在如何修改。之前的教程直接查找dex的字符串【管理员】好像已经不管用了,因为里面已经没有穿山甲的相关代码了。查看开发文档,实际上广告放在了安装包的assets目录下。
1.png (46.8 KB, 下载次数: 1)
下载附件
2022-1-8 22:49 上传
如上图,这个md5是一个apk文件,用winrar打开后是apk的结构。里面的dex就是广告sdk。搜了一下字符串,果然还是熟悉的3个【管理员】。因为他已经单独分离出来了,所以直接删掉这个安装包就好了。
AndroidManifest
中也有不少腾讯广告的权限。
权限列表:
[Asm] 纯文本查看 复制代码
以上这些权限全删。然后assets目录下的
gdt_plugin文件夹、bdxadsdk.jar、39285EFA.dex
也全部删掉。
修改完毕后重新安装,现在还有个广告是百度的青藤。
1.png (360.85 KB, 下载次数: 1)
下载附件
2022-1-8 23:10 上传
和以往稍有不同,不过都大同小异。反编译dex,百度广告sdk一般在com/baidu/mobads/sdk,广告sdk混淆后会导致异常,所以一般来说这些广告文件都是固定的目录,基本上不会变。百度广告有个类名叫做
SplashAd
,翻译过来就是开屏广告,位于com/baidu/mobads/sdk/api/SplashAd。进入后找到.method public final load()V和.method public loadAndShow(Landroid/view/ViewGroup;)V。
loadAndShow的源码:
public void loadAndShow(ViewGroup viewGroup) {
if (viewGroup == null) {
SplashAdListener splashAdListener = this.mListener;
if (splashAdListener != null) {
splashAdListener.onAdFailed("传入容器不可以为空");
}
} else if (this.mIsAdaptiveSplashAd) {
SplashAdListener splashAdListener2 = this.mListener;
if (splashAdListener2 != null) {
splashAdListener2.onAdFailed("使用自适应开屏广告能力, 需要使用showWithBottomView方法并传入合适尺寸的底部logo");
}
} else {
addZeroPxSurfaceViewAvoidBlink(viewGroup, this.mContext);
bz bzVar = new bz(this.mContext);
bzVar.a(new 3(this, bzVar));
bzVar.setLayoutParams(new ViewGroup.LayoutParams(-1, -1));
viewGroup.addView(bzVar);
}
}
loadAndShow翻译过来就是加载和展示。去广告一般的做法就是代码全删,load()V和loadAndShow(Landroid/view/ViewGroup;)V直接return-void就可以了,不过我习惯是先查看这些代码调用了哪些方法,把这些方法删了再清空。
1.png (57.88 KB, 下载次数: 1)
下载附件
2022-1-9 10:24 上传
那么这样开屏广告就不见了。虽然去掉了开屏广告,但是阅读页的底部还是有广告横幅,这样又要去翻一遍代码清除了。那有没有一遍过的方法呢?有。
早些时候我发过一个去广告的教程,是搜索方法名addEventListener,现在也是可以适用的,不过路径稍稍有些改变。addEventListener是什么函数有兴趣的可以自己百度。
dex反编译后直接搜索百度sdk的代码【addEventListener】,有很多个结果。
1.png (86.33 KB, 下载次数: 0)
下载附件
2022-1-9 10:51 上传
红框的几个类名是广告联网的老巢,七猫小说的话n()V直接返回void就能去掉开屏广告和阅读页底部的横幅广告了。为了保险起见,其它的也应该都全部删掉。去掉广告后有些地方有广告布局,怎么修改这些布局之前出过教程,这里就不再重复一次了。
除此之外,在 主页→我的 还有个“抽大奖”的图标。我实在想不通为什么要在这里设计一个图标,横幅已经有个入口了,为啥还要另外搞一个,虽然叫幸运大转盘。这是怕别人不识字吗?
1.png (87.37 KB, 下载次数: 0)
下载附件
2022-1-9 12:03 上传
根据布局名称,home_float_ad_layout是显示抽大奖的id。dex里的值为0x7f0903a3,搜索它,定位到com/kmxs/reader/home/view/HomeScreenPopupView,把k(Landroid/view/View;)V这个方法的代码全删即可去掉那个烦人的图标。
1.png (45.09 KB, 下载次数: 0)
下载附件
2022-1-9 12:10 上传