unidbg取巧解ollvm题一例

admin 2024年5月14日23:20:04评论8 views字数 2660阅读8分52秒阅读模式

unidbg取巧解ollvm题一例

前言

是去年的一道题,之前是用模拟执行试图去掉混淆,然后用frida爆破取巧做出来,这次改用unidbg进行分析,针对这种flag按位判断的题,较快定位判断点。后面就是unidbg hook进行爆破。
之前还要考虑反调试,frida检测,这次使用unidbg就没有那么多顾虑了。

分析App

直接拖进jadx,MainActivity内容如下,代码不多,基本流程就是,获取输入字符,通过一个native层的checkflag判断输入是否正确:
unidbg取巧解ollvm题一例

把so直接放进ida,混淆没法看。
unidbg取巧解ollvm题一例这里开始先不看ida了,先用unidbg执行一遍。

Unidbg模拟执行

搭好架子,直接跑,不用补环境一次通。
这里不知道flag长度,可以先跑一次,把长度爆破出来。
unidbg取巧解ollvm题一例只需要记录下执行的汇编指令数量,就可以根据执行数量来判断flag的长度。这里用unicorn的方式hook记录,

  1. ........

  2. publicboolean checkcode(String p1)throwsFileNotFoundException{

  3. emulator.getBackend().hook_add_new(newCodeHook(){

  4. @Override

  5. publicvoid hook(Backend backend,long address,int size,Object user){

  6. list.add(address);

  7. }

  8. @Override

  9. publicvoid onAttach(UnHook unHook){

  10. }

  11. @Override

  12. publicvoid detach(){

  13. }

  14. },module.base+0x93CC,module.base+0x93CC+0x4844,null);

  15. String methodDec ="checkflag(Ljava/lang/String;)Z";

  16. boolean obj = timuclass.callStaticJniMethodBoolean(emulator, methodDec, p1);

  17. System.out.println(p1.length()+"----"+ list.size());

  18. list.clear();

  19. return obj;

  20. }

  21. ........

  22. publicstaticvoid main(String[] args)throwsException{

  23. MainActivity t =newMainActivity();

  24. int length =40;

  25. StringBuilder stringBuilder =newStringBuilder(length);

  26. String result ="";

  27. for(int i =0; i < length; i++){

  28. stringBuilder.append("0");

  29. result = stringBuilder.toString();

  30. t.checkcode(result);

  31. }

  32. // System.out.println(t.checkcode("fla0000000000002"));

  33. }

  34. }

跑了一下,可以明显看到16的时候执行的代码量相比前面的递增1400左右要多了不少,大概就能看出来flag的长度应该是16。
unidbg取巧解ollvm题一例此时已经知道flag的长度,可以填充,假设flag最后是flag{xxxxx},则按位尝试,形如f000000000000000,fl00000000000000,fla0000000000000,去获取对应执行的地址,并记录日志,然后对比执行的地址差异:
unidbg取巧解ollvm题一例分别执行完0000000000000000,f000000000000000,fl00000000000000,在vscode中对比日志,发现后者多了很多执行地址:
unidbg取巧解ollvm题一例将多执行的地址抠出来,再对比,发现是约840条重复执行,这里其实就能看出来是在按位比较,错一位就跳出,16位flag应该会有16轮比较:
unidbg取巧解ollvm题一例进一步分析循环判断的地址,结合ida,这里我选择从底往上回溯,可以看到一连串连续看了下F5后看不出东西继续往上找,找到不连续的地方应该是B跳转过来。
unidbg取巧解ollvm题一例找到一个不一样的跳转,但是没有多代码,继续往上
unidbg取巧解ollvm题一例在这一处发现有判断的代码了。
unidbg取巧解ollvm题一例F5下,可以看到根据判断结果,赋值v429,这时候再往下看看:
unidbg取巧解ollvm题一例会跳入0xdc08,然后直接到0x9464,最后赋值给v425,即上面判断的关键变量:
unidbg取巧解ollvm题一例此时可以尝试在上面的判断处去hook寄存器值,输入定长flag,按位进行爆破。

unidbg爆破

这里so是armv64,我用dobby进行hook。

  1. ......

  2. Dobby dobby =Dobby.getInstance(emulator);

  3. dobby.instrument(module.base+0xBDC0,newInstrumentCallback<Arm64RegisterContext>(){

  4. @Override

  5. publicvoid dbiCall(Emulator<?> emulator,Arm64RegisterContext ctx,HookEntryInfo info){

  6. long w13 = ctx.getXLong(13);

  7. long w14 = ctx.getXLong(14);

  8. if(w13 == w14){

  9. index++;

  10. }

  11. }

  12. });

  13. ......

  14. privatevoid crack()throwsFileNotFoundException{

  15. String flag ="";

  16. for(int i =0; i <16; i++){

  17. for(int ch =32; ch <127; ch++){

  18. index =0;

  19. String str =(flag +(char) ch +"~~~~~~~~~~~~~~~~").substring(0,16);

  20. boolean success = checkcode(str);

  21. if(success || i +1== index){

  22. flag +=(char) ch;

  23. System.out.println(flag);

  24. break;

  25. }

  26. }

  27. }

  28. }

  29. ......

先用占位符凑16位长度,按位爆破,很快就能跑出来。
unidbg取巧解ollvm题一例

总结

针对这种ollvm的逆向题,要花时间用trace去还原算法难度确实好大(我很菜),要老老实实的去看tracelog中的寄存器变化跟出结果。但是在这一例中,flag最后是通过按位去比较得出的,这里我取巧是通过了对比不同输入下重复执行的指令地址去定位flag比较的指令地址,不能说是个很好的通用方法,但是确实能在一定程度上简化了分析的流程。

原文始发于微信公众号(gakki的童养夫):unidbg取巧解ollvm题一例

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年5月14日23:20:04
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   unidbg取巧解ollvm题一例https://cn-sec.com/archives/2058392.html

发表评论

匿名网友 填写信息