之前的几个小练习都是停留在smali层,今天尝试使用IDA分析修改一个so。
简单的安装体验一下,只有一个登陆页面。输入用户名和密码点击登录然后弹对应的toast。
一、首先反编译apk
代码很简单,只有一个注册按钮的点击事件,然后在里面调用了一个myJNI.check的native方法:
public class MainActivity
extends AppCompatActivity
{
EditText User_Name;
EditText User_Pass;
Context ct = this;
myJNI mj = new myJNI();
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968603);
this.User_Name = ((EditText)findViewById(2131427416));
this.User_Pass = ((EditText)findViewById(2131427417));
((Button)findViewById(2131427418)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
Toast.makeText(MainActivity.this, MainActivity.this.mj.check(MainActivity.this.ct, MainActivity.this.User_Name.getText().toString().trim(), MainActivity.this.User_Pass.getText().toString().trim()), 0).show();
}
});
}
}
public class myJNI
{
static
{
System.loadLibrary("JniTest");
}
public native String check(Object paramObject, String paramString1, String paramString2);
}
重新打包安装再试一下,点击登录后直接闪退了,说明在so层做了某种验证。
二、分析so
找到JniTest.so文件,丢进IDA中。先简单介绍下IDA的两个窗口
1、Exports窗口是导出表(so中能让外部调用的函数)
2、Imports窗口是导入表(so调用到外面的函数)
这里因为我们知道了在Java层调用了一个check方法,因此我们在Exports导出表窗口中搜索check,就能定位到我们需要的函数了:Java_demo2_jni_com_myapplication_myJNI_check。
点击函数后按下空格键,就能看到其流程图了。
不过我们发现有个别的地方是识别的不是很好,我们手动修复一下。
#完整的代码
text:00000EB8 EXPORT Java_demo2_jni_com_myapplication_myJNI_check
.text:00000EB8 Java_demo2_jni_com_myapplication_myJNI_check
.text:00000EB8 ; DATA XREF: LOAD:000001FC↑o
.text:00000EB8
.text:00000EB8 userPassword = 0
.text:00000EB8
.text:00000EB8 ; __unwind {
.text:00000EB8 PUSH.W {R4-R8,LR}
.text:00000EBC MOV R4, R0
.text:00000EBE MOV R7, R3
.text:00000EC0 BL getSignature
.text:00000EC4 LDR R2, [R4]
.text:00000EC6 LDR.W R3, [R2,#0x2A4]
.text:00000ECA MOVS R2, #0
.text:00000ECC MOV R1, R0
.text:00000ECE MOV R0, R4
.text:00000ED0 BLX R3
.text:00000ED2 LDR R2, [R4]
.text:00000ED4 MOV R1, R7
.text:00000ED6 LDR.W R5, [R2,#0x2A4]
.text:00000EDA MOVS R2, #0
.text:00000EDC MOV R6, R0
.text:00000EDE MOV R0, R4
.text:00000EE0 BLX R5
.text:00000EE2 LDR R3, [R4]
.text:00000EE4 LDR R1, [SP,#0x18+userPassword]
.text:00000EE6 MOVS R2, #0
.text:00000EE8 LDR R5, =(aJniLog - 0xEF2)
.text:00000EEA LDR.W R3, [R3,#0x2A4]
.text:00000EEE ADD R5, PC ; "JNI_LOG"
.text:00000EF0 MOV R8, R0
.text:00000EF2 MOV R0, R4
.text:00000EF4 BLX R3
.text:00000EF6 LDR R2, =(aJniS - 0xF00)
.text:00000EF8 MOV R1, R5
.text:00000EFA MOV R3, R6
.text:00000EFC ADD R2, PC ; "JNI获取到的签名是%s"
.text:00000EFE MOV R7, R0
.text:00000F00 MOVS R0, #4
.text:00000F02 BLX __android_log_print
.text:00000F06 LDR R1, =(a308201dd308201 - 0xF0E)
.text:00000F08 MOV R0, R6 ; s1
.text:00000F0A ADD R1, PC ; "308201dd30820146020101300d06092a864886f"...
.text:00000F0C BLX strcmp
.text:00000F10 CBNZ R0, loc_F2E
.text:00000F12 LDR R2, =(asc_23A6 - 0xF1C)
.text:00000F14 MOV R1, R5
.text:00000F16 MOVS R0, #4
.text:00000F18 ADD R2, PC ; "签名一致"
.text:00000F1A BLX __android_log_print
.text:00000F1E LDR R1, =(aKoudai - 0xF26)
.text:00000F20 MOV R0, R8 ; s1
.text:00000F22 ADD R1, PC ; "koudai"
.text:00000F24 BLX strcmp
.text:00000F28 LDR R5, [R4]
.text:00000F2A CBZ R0, loc_F40
.text:00000F2C B loc_F58
.text:00000F2E ; ---------------------------------------------------------------------------
.text:00000F2E
.text:00000F2E loc_F2E ; CODE XREF: Java_demo2_jni_com_myapplication_myJNI_check+58↑j
.text:00000F2E LDR R2, =(asc_23BA - 0xF38)
.text:00000F30 MOVS R0, #4
.text:00000F32 MOV R1, R5
.text:00000F34 ADD R2, PC ; "签名不一致 退出程序"
.text:00000F36 BLX __android_log_print
.text:00000F3A MOVS R0, #0 ; status
.text:00000F3C BLX exit
.text:00000F40 ; ---------------------------------------------------------------------------
.text:00000F40
.text:00000F40 loc_F40 ; CODE XREF: Java_demo2_jni_com_myapplication_myJNI_check+72↑j
.text:00000F40 LDR R1, =(aBlack - 0xF48)
.text:00000F42 MOV R0, R7 ; s1
.text:00000F44 ADD R1, PC ; "black"
.text:00000F46 BLX strcmp
.text:00000F4A CBNZ R0, loc_F58
.text:00000F4C LDR R1, =(asc_23DD - 0xF58)
.text:00000F4E MOV R0, R4
.text:00000F50 LDR.W R3, [R5,#0x29C]
.text:00000F54 ADD R1, PC ; "登陆成功"
.text:00000F56 B loc_F62
.text:00000F58 ; ---------------------------------------------------------------------------
.text:00000F58
.text:00000F58 loc_F58 ; CODE XREF: Java_demo2_jni_com_myapplication_myJNI_check+74↑j
.text:00000F58 ; Java_demo2_jni_com_myapplication_myJNI_check+92↑j
.text:00000F58 LDR R1, =(asc_23EA - 0xF64)
.text:00000F5A MOV R0, R4
.text:00000F5C LDR.W R3, [R5,#0x29C]
.text:00000F60 ADD R1, PC ; "登陆失败"
.text:00000F62
.text:00000F62 loc_F62 ; CODE XREF: Java_demo2_jni_com_myapplication_myJNI_check+9E↑j
.text:00000F62 BLX R3
.text:00000F64 POP.W {R4-R8,PC}
.text:00000F64 ; End of function Java_demo2_jni_com_myapplication_myJNI_check
最终得到比较容易识别的代码。这里我们可以很明显的看到调用了一个getSignature方法,并在00000F0C位置与一个字符串做对比。接下来看00000F10位置的CBNZ操作,这里判断如果签名信息一致,则进入loc_F2E分支最后执行exit退出app。
还是简单的介绍下这个指令:
名字 | 功能 |
---|---|
CBZ | 比较,如果结果为零(Zero)就转移(只能跳到后面的指令) |
CBNZ | 比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令) |
看到这儿,我们就有思路了,想要要过签名验证,我们只需要把CBNZ指令改成CBZ就可以了。查看对应的16进制:
通过查找对应的指令码,我们把B9修改成B1:
然后返回到反编译页面,就能看到我们成功的把CBNZ指令改成了CBZ。这样,即便签名不一致,也不会执行退出app的逻辑
保存修改,重新打包app,这时候再次点击登录按钮,边不会出现退出app的情况了。
我们再进一步,想要输入其他任意用户名和密码也能弹出成功登录的toast。
text:00000F2A CBZ R0, loc_F40这里对用户名做了判断,如果不等于“koudai”,则跳转loc_F58分支最后展示登陆失败。同样的道理,我们把指令由CBZ改成CBNZ,让分支跳转到loc_F40。
.text:00000F4A CBNZ R0, loc_F58,这里对用户密码做了验证,如果不等于"black",则跳转loc_F58分支最后展示登陆失败。这里我们把CBNZ指令改成CBZ。最后重新打包apk,输入任意用户名和密码测试一下:
Demo apk文件
链接: https://pan.baidu.com/s/1sHUvgo3twq7uAVXfTN2I5Q
密码: e3t6
关注获取更多
网友评论