白乐天

道阻且长,行则将至。

自毁程序密码—阿里聚安全

App信息

包名:com.yaotong.crackme

Java层分析

MainActivity

很容易就能看出来是在securityCheck函数里进行安全校验。securityCheck是一个native函数,到so中进行分析。

SO层分析

定位函数位置

在导出函数里搜索

securityCheck

数据类型修复和重命名后的securityCheck

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int __fastcall Java_com_yaotong_crackme_MainActivity_securityCheck(JNIEnv *a1, jobject a2, char *str)
{
 const char *inputStr; // r0
 char *wojiushidaan; // r2
 int tempResult; // r3
 int v8; // r1

 if ( !byte_6359 )
{
   sub_2494(byte_6304, 8, &unk_446B, &unk_4468, 2, 7);
   byte_6359 = 1;
}
 if ( !byte_635A )
{
   sub_24F4(byte_636C, 25, &unk_4530, &unk_4474, 3, 117);
   byte_635A = 1;
}
 _android_log_print(4, byte_6304, byte_636C);
 inputStr = (*a1)->GetStringUTFChars(a1, str, 0);
 wojiushidaan = off_628C;
 while ( 1 )
{
   tempResult = *wojiushidaan;
   if ( tempResult != *inputStr )
     break;
   ++wojiushidaan;
   ++inputStr;
   v8 = 1;
   if ( !tempResult )
     return v8;
}
 return 0;
}

off_628C

进入off_628C偏移查看,它的内容是”wojiushidaan”

数据查看

结合securityCheck函数分析,我觉得这就是正确答案了。

可是输入之后,还是校验失败。

无奈只能动态调试

动态调试

IDA动态调试环境配置这里不再介绍。

附加进程

重新启动程序

在IDA里选择附加到进程

附加进程之后,我们运行一下,会发现,程序崩了,IDA也崩了,说明这个so是有反调试的。

反调试绕过

猜测反调试是通过线程进行循环检测的。

打开线程窗口

发现一个线程yaotong.crackme,有点可疑,右键这个线程,将状态改为suspend,暂停这个线程。

然后运行,程序没有挂掉,可以进行调试。

断点调试

打开Modules窗口,找到libcrackme.so,双击进去,找到securityCheck函数,双击该函数跳转到函数的位置。

在这个函数起始的位置下一个断点,将光标移动到断点位置,按下快捷键F,然后在输入框输入任意数据,点击输入密码,程序就会运行到断点位置。

F5查看反汇编,找到原来的变量偏移地址处,发现数据变了,变成了aiyou,bucuoo

验证

aiyou,bucuoo放进输入框,点击输入密码,跳转到成功界面。

使用frida hook内存

找到存储答案的变量的内存地址

在程序启动之后,使用frida直接对内存进行hook

1
2
3
4
5
function hook_yaotong(){
var soAddr = Module.findBaseAddress("libcrackme.so");
var hookAddr = soAddr.add(0x4450)
console.log(hookAddr.readCString())
}

使用unidbg模拟执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.yaotong.crackme;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.DynarmicFactory;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;
import java.io.File;


public class MainActivity extends AbstractJni {
private final AndroidEmulator emulator;
private final Memory memory;
private final VM vm;
private final DalvikModule dalvikModule;
private final Module module;

MainActivity() {
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.yaotong.crackme").addBackendFactory(new DynarmicFactory(true)).build();
memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/yaotong/crackme/alijuanquan.apk"));
vm.setJni(this);
vm.setVerbose(true);
dalvikModule = vm.loadLibrary("crackme",true);
module = dalvikModule.getModule();
vm.callJNI_OnLoad(emulator,module);
}
public static void main(String[] args) {
MainActivity test = new MainActivity();
System.out.println(test.Check());
}
public Boolean Check() {
DvmClass dvmClass = vm.resolveClass("com.yaotong.crackme.MainActivity");
DvmObject dvmObject = dvmClass.newObject(null);
String input = "aiyou,bucuoo";
boolean result = dvmObject.callJniMethodBoolean(emulator,"securityCheck(Ljava.lang.sring;)Z",input);
System.out.println("result=" + result);
return result;
}
}

待完善…

参考文章:https://mp.weixin.qq.com/s/r-XXZQImgRc-Lce5B7x60w