查看原文
其他

记使用Trace还原ollvm混淆的函数

neilwu 看雪学苑 2022-07-01


本文为看雪论坛优秀文章

看雪论坛作者ID:neilwu





一、前言


1、题目


https://bbs.pediy.com/thread-260650.htm
https://bbs.pediy.com/thread-260655.htm
 
二位大佬的两种解题思路,膜拜膜拜。


2、这篇帖子你会看到什么


ollvm可以使用IDA的trace功能辅助还原,看到样本上手尝试一下。

上面的帖子中有部分使用trace进行辅助还原,这篇帖子是通过trace后的汇编指令进行的ollvm还原过程,记录分享一下过程,不喜勿喷。


3、IDA trace功能



(1)Instruction tracing


调试器将为每条指令保存所有修改后的寄存器值。
https://www.hex-rays.com/products/ida/support/idadoc/1446.shtml


(2)Basic block tracing


调试器将保存到达临时基本块断点的所有地址。
https://www.hex-rays.com/products/ida/support/idadoc/1628.shtml


(3)Function tracing


调试器将保存发生函数调用或函数返回的所有地址。
https://www.hex-rays.com/products/ida/support/idadoc/1447.shtml





二、还原ollvm混淆函数过程


1、对应到还原函数 sub_13CE4


 
定位过程可以参考上面2个帖子。


2、通过frida进行函数调用


function call_13CE4() { var base_xxx = Module.findBaseAddress("libnative-lib.so")
if(base_xxx){ var addr_13CE4 = base_xxx.add(0x13CE4) console.log("0x13CE4 :", addr_13CE4) var sub_13CE4 = new NativeFunction(addr_13CE4, "void", ["pointer", "int", "pointer", "int", "pointer"])
var input1_str = "pediy_imyang_lXcaTALmow" var input1_buffer = Memory.allocUtf8String(input1_str) var input2_str = "www.pediy.com&kanxue" var input2_buffer = Memory.allocUtf8String(input2_str)
var result = Memory.alloc(0x26);// 38
console.log("input1_str len ", input1_str.length) console.log("input2_str len ", input2_str.length)
sub_13CE4(input1_buffer,input1_str.length,input2_buffer,input2_str.length,result) console.log(hexdump(result, {length: result.length})) }}

结果显示:

 
参数:

参数1 pediy_imyang_lXcaTALmow参数2 23参数3 www.pediy.com&kanxue参数4 20参数5 结果地址

结果:

79 79 03 09 00 01 a4 b8 b6 c8 9e b4 7f 4f 29 b4 4d 47 c7 38 2f 85 1a d5 76 18 f9 b8 20 c5 d5 52 98 cb 5f 94 1c 8c

3、在0x13CE4和函数结束的位置0x下断点,trace出来函数中汇编


 
trace后的cfg,变黄色就是执行的汇编指令被trace过:


sub_13CE4中调用了sub_13808和sub_172D0。


4、分析trace文件


(1)分析参数1


参数1 pediy_imyang_lXcaTALmow



对应trace文件:



以 0x0000000000000070看一下具体处理:



参数1 中的 0x70 -> 0x51,是通过如下进行的查询0x70的位置是0x51。



最终结果为:


参数1:



加密后:


(2)分析参数3


参数3 www.pediy.com&kanxue:

 


trace文件中参数3只用了16个字符进行后续的处理。

这里的处理和参数1处理的方式相同:

 
 
参数3:



加密后:


(3)结果生成


使用参数1加密后的字节和参数3加密后的字节进行计算加密生成结果

图一

图一是 参数1加密字节0x00000000514D43F9 和 参数3加密字节 0x00000000F5F5F531 生成的结果是 0x00000000A4B8B6C8。

图二

图二是 参数1加密字节0x00000000b6cff93c 变形为 00000000CFF93CB6 (未参与加密)。

参数3加密字节 0x00000000514d43f9 和 常数 0x0000000068DE32AA 加密乘车生成的结果是 0x000000009EB47F4F。

图三

图三是 参数1加密字节0x00000000b6ef9f85 变形为 0x000000009F85B6EF,

以及参数3加密字节 0x00000000B631FBA8 生成的结果是 0x0000000029B44D47。

图四

图三是 参数1加密字节0x00000000cf506afb 变形为 0x00000000FBCF506A,

和以及参数3加密字节 0x000000003CF77FEF 生成的结果是 0x00000000C7382F85。

拼接结果:
A4B8B6C8 9EB47F4F 29B44D47 C7382F85

和结果对比:
 
797903090001 a4b8b6c8 9eb47f4f 29b44d47 c7382f85 1ad57618 f9b820c5 d55298cb 5f941c8c
 
根据以上的分析可以得到算法如下:

参数1加密后字节:

514d43f9 b6cff93c b6ef9f85 cf506afb ef208329 3ca8f563 63636363 63636363

参数3加密字节:

f5f5f531 514d43f9 b631fba8 3cf77fef f5f5f531 514d43f9 b631fba8 3cf77fef

循环8次参数1加密后字节会随着循环次进行变化0次 514d43f9 -> 514d43f91次 b6cff93c -> cff93cb62次 b6ef9f85 -> 9f85b6ef 3次 cf506afb -> fbcf506a....这是有规律的根据循环进行的变化
在第1次和第5次的时候参数1加密后字节只是做的了变形 未参加加密参数3加密字节与常量0x0000000068DE32AA进行了加密其他循环中都是参数1加密后字节与参数3加密字节进行加密操作

以图一为例,计算如下:

X8 = 0x00000000f5f5f531
X9 = 0x0000000514d43f9
W11 = X8 & (X8^X9)
w8 = X9&(X9^X8)
w8 = 0xa4b8b6c8

797903090001 这个值的赋值可以通过2种方式:

方法一:动态调试的时候 x4指向的地址 前六为是固定的 直接可以拿到(多次调试的结果);

方法二:trace中找赋值过程。


以上就是通过对trace的汇编指令进行的ollvm函数还原,按以上信息可以写出算法,偷懒先不写了,可以看一下上面的帖子。




三、总结


1、trace的分析还需要继续加深学习和掌握,上面的分析中对内存中连续值的赋值和拼装找的还不是很好;

2、非常感谢看雪论坛,故把分析过程分享给大家;

3、这都是大佬的经验之谈,牛逼牛逼。

 



- End -



看雪ID:neilwu

https://bbs.pediy.com/user-home-590753.htm

  *本文由看雪论坛 neilwu 原创,转载请注明来自看雪社区。





本文参与了#看雪30天发帖打卡挑战#活动。


发帖见证成长,坚持见证不凡。


不仅可以收获进步,还可赢取物质奖励哦!


想要了解更多活动详情,戳 ↓




推荐文章++++

* 高版本64位Win10(RS2或更高)下枚举消息钩子的一种思路

* X64内核SMAP,SMEP浅析

* Linux Kernel Pwn 学习笔记 (UAF)

* Linux-5.6.6 内核引导

* 崩溃回溯分析







公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



求分享

求点赞

求在看


“阅读原文”一起来充电吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存