逆向libbaiduprotect(四)
百度加固libbaiduprotect.so自身对只读字符串进行了加密保护,防止成为破解和逆向的切入口。一般地认为,只要找出这个解密算法就可以对.rodata段的只读字符串进行破解,从而窥探程序的意图。定位解密的位置不难,但是百度使用了多重匹配的手段,有力地加强了难度,因为解密的函数不是一个,而是一组。对于一个字符串只可以被其中一个解密函数解密。如果有M个字符串,N个解密函数,那么就是MxN的组合。首先你要定位出不是一处解密函数,而是N个解密函数,并且N为未知。确定后,有MxN个可能解密的字符串,必须过滤掉Mx(N-1)个不正确的解密字符串。这样还不止,百度加固还使用了另一种手段,使得破解都不在字符串的加密字节流的首字节开始进行的解密失败。

上图的左侧是一段运行中的代码片段,这段代码接踵地调用字符串解密函数,并将解密后的字符串传入下一个函数进行调用。划红线的三处就是解密函数,可以看到是不同的函数地址。在图的中间,是我的gdb调试过程,将左侧的三处函数地址分别存放在$func,$func3和$func4变量中,并类型转换成函数指针放在$f, $f3, $f4变量中。将左侧图的加密字符串地址计算出分别存放在$27, $f3_arg, $f4_arg中。分别执行$f($27), $f3($f3_arg), $f4($f4_arg),得到结果"libc.so", "_exit", "exit"。 这里还有另外两处的解密函数和加密字符串,$f1($50)和$f2($57),它的结果是"libdl.so"和"pwrite"。当我将使用$f2去解密$50时,解密失败了。解密的函数还有许多,就是开篇时说的未知数N。
下面我懒得去逆向分析,直接将其中的一个解密函数dump出来,并且在正在调试libbaiduprotect.so的移植python上映射一个执行区,然后直接去调用。

由于解密函数内部调用了其它库的函数,符号连接没有做处理,访问出错,只要处理好符号连接就可以直接使用里面的解密函数?
还不行,每个解密函数还单独对应一组密钥窗口。
下面摘取其中一个解密函数进行逆向分析:
0xad9dd430: push %ebp
0xad9dd431: push %ebx
0xad9dd432: push %edi
0xad9dd433: push %esi
0xad9dd434: sub $0xc,%esp ; 距离上一栈帧 0x1c
0xad9dd437: call 0xad9dd43c
0xad9dd43c: pop %ebx ; %ebx = %eip // 使用eip定位全局变量
0xad9dd43d: add $0x72a98,%ebx ; %ebx = 0xad9dd43c + 0x72a98
0xad9dd443: mov 0x20(%esp),%esi ; %esi = arg_1 // 函数输入加密编码字符串
0xad9dd447: lea -0x1(%esi),%edi ; while(*(((char*)%edi++)+1) != 0); // 计算加密字节流长度
0xad9dd450: cmpb $0x0,0x1(%edi)
0xad9dd454: lea 0x1(%edi),%edi
0xad9dd457: jne 0xad9dd450
0xad9dd459: sub %esi,%edi ; %edi = (int) ((char*)%edi - (char*)%esi)
0xad9dd45b: shr %edi ; %edi >>= 1
0xad9dd45d: lea 0x1(%edi),%eax ; %eax = %edi + 1 // 解码字符串长度
0xad9dd460: mov %eax,(%esp)
0xad9dd463: call 0xad9c2810 <malloc@plt> ; char* var_8 = (char*) malloc(%eax)
0xad9dd468: mov %eax,0x8(%esp)
0xad9dd46c: movb $0x0,(%eax,%edi,) ; var_8 [ %edi ] = 0
0xad9dd470: mov (%esi),%cl ; %cl = *(char*)%esi
0xad9dd472: test %cl,%cl ; if (%cl != 0) {
0xad9dd474: je 0xad9dd4ca
0xad9dd476: add $0x2,%esi ; %esi += 2
0xad9dd479: xor %eax,%eax ; %eax = 0 // 常量0
0xad9dd47b: xor %edi,%edi ; %edi = 0 // 用作计数器,[0, 7],指定解码的key
0xad9dd47d: mov 0x8(%esp),%ebp ; %ebp = var_8 // 用作遍历 var_8 的指针
0xad9dd490: movsbl %cl,%edx ; %edx = (int) %cl // 下一轮循环入口,也就是解码下一对加密字符
0xad9dd493: shl $0x4,%cl ; %cl <<= 4
0xad9dd496: cmp $0x3a,%edx ; if (%edx >= 0x3a) {
0xad9dd499: jl 0xad9dd49e
0xad9dd49b: add $0x90,%cl ; %cl += 0x90
0xad9dd49e: movsbl -0x1(%esi),%edx ; } %edx = (int) *(char*)(%esi - 1) // 紧接配对的下一个加密字符
0xad9dd4a2: cmp $0x3a,%edx ;
0xad9dd4a5: mov $0xd0,%ch ; %ch = 0xd0
0xad9dd4a7: jl 0xad9dd4ab ; if (%edx >= 0x3a) {
0xad9dd4a9: mov $0xc9,%ch ; %ch = 0xc9
0xad9dd4ab: add %dl,%cl ; } %cl += %dl
0xad9dd4ad: add %ch,%cl ; %cl += %ch // 化简 %cl += %dl + (%edi >= 0x3a) ? 0xc9 : 0xd0
0xad9dd4af: cmp $0x8,%edi ;
0xad9dd4b2: cmove %eax,%edi ; %edi = (0x8 == %edi) ? %eax : %edi // %eax 这时为0
0xad9dd4b5: xor -0x138df(%ebx,%edi,),%cl; %cl ^= 一个全局变量 // 一组解码的key,每个字符的解码相应一个key,滚动使用一个key窗口,防破解
0xad9dd4bc: mov %cl,0x0(%ebp) ; *(char*) %ebp = %cl
0xad9dd4bf: inc %ebp ; %ebp++
0xad9dd4c0: inc %edi ; %edi++
0xad9dd4c1: mov (%esi),%cl ; %cl = *(char*) %esi // 下一对加密字符的第一个字符
0xad9dd4c3: add $0x2,%esi ; %esi += 2
0xad9dd4c6: test %cl,%cl ; if (%cl != 0)
0xad9dd4c8: jne 0xad9dd490 ; goto 0xad9dd490 // 循环
0xad9dd4ca: mov 0x8(%esp),%eax ; } %eax = var_8
0xad9dd4ce: add $0xc,%esp ;
0xad9dd4d1: pop %esi
0xad9dd4d2: pop %edi
0xad9dd4d3: pop %ebx
0xad9dd4d4: pop %ebp
0xad9dd4d5: ret ; return (char*) %eax
上面的反汇编逻辑并不难,完全不借助工具分析也可以手工逆向。
工作原理:
1.字符串每个字符被加密成一个双字节,并以0结束。一个n长度的字符串,它的加密字节串长度为2n,然后以0作为额外结束符。
2.解密一个字符,必须参照一双加密字节,解密出一个字节。然后还要将这个得出的字节,使用密钥字节进行异或才能最后还原出正确的字符。
3.使用一组总数为8的密钥窗口,对解密过程进行滚动使用。每个字符的解密都对应其中的一个密钥。
从上面的工作原理可以有这样的解密失配的结果:
1.当一个偶地址开始的加密字节串,如果在其中中间的某个奇地址开始进行解密的话,解密过程中,由双字节得到单字节都将是错误的,因这过程的双字节失配了。反之亦然。
2.即使双字节没有失配,如果加密字节串的起始地址没有与密钥窗口对上,同样字符的解密失败。比如说我们在加密字节串起始地址偏移了2*n个单位进行解密,则会解密错误。
3.当每个解密函数使用独立的密钥窗口时,加密字节串就必须使用相配的密钥窗口的解密函数才能将字符串解密出来。
4.当你不清楚每个加密字节串的起始地址,而暴力破解时,那不是M个字符串 x (N个解密函数 - 1) 次失配了,而 .rodata长度 x (N个解密函数)- M个字符串 次失配。尽管我们可以假定每个加密字节串的起始位于前一个加密字节串的结束符之后,来减少暴力次数,但也只是假定。
逆向libbaiduprotect(四)的更多相关文章
- 逆向libbaiduprotect(二)
首先要确保你所使用的gdb和gdbserver是配对的,最好(或必须)是sdk内相同platform(api level)下的gdb和gdbserver.否则你使用的gdb可能与运行测试机上的gdbs ...
- Python逆向(四)—— Python内置模块dis.py源码详解
一.前言 上一节我们对Python编译及反汇编做了讲解,大家知道dis模块可以将编译好的pyc文件中提取出来的PyCodeObject反汇编为可以阅读字节码形式.本节我们对dis模块中的源码进行详细的 ...
- 南邮攻防训练平台逆向第四题WxyVM
下载文件elf文件,运行输入flag,用ida打开逆向算法: 不是很复杂,可以看出flag长度需要24,最终会和已给出dword_601060进行比较,一致则成功,那么现在只需要看上面的sub_400 ...
- 逆向libbaiduprotect(三)- 移植python操作dalvik虚拟机c++函数,配合gdb控制程序运行流程
python编译移植到测试机,并且移植ctypes模块.利用ctypes代替c程序,利用dalvik内部c++函数,在运行过程中手动命令操控dalvik虚拟机,并结合gdb进行调试.绕过zygote和 ...
- iOS逆向(五)-ipa包重签名
为什么要重签名? 1.在没有源代码的情况下,你已经对某个应用进行了资源修改(比如修改了启动图或图标等).修改完成以后,如果想要让APP可以正常使用,该APP一定要重新签名然后压缩成IPA文件. 2.如 ...
- Python逆向(一)—— 前言及Python运行原理
一.前言 最近在学习Python逆向相关,涉及到python字节码的阅读,编译及反汇编一些问题.经过长时间的学习有了一些眉目,为了方便大家交流,特地将学习过程整理,形成了这篇专题.专题对python逆 ...
- 【二进制】【WP】MOCTF逆向题解
moctf 逆向第一题:SOEASY 这个是个 64 位的软件,OD 打不开,只能用 IDA64 打开,直接搜字符串(shift+F12)就可以看到 moctf 逆向第二题:跳跳跳 这个题当初给了初学 ...
- 逆向知识第十四讲,(C语言完结)结构体在汇编中的表现形式
逆向知识第十四讲,(C语言完结)结构体在汇编中的表现形式 一丶了解什么是结构体,以及计算结构体成员的对其值以及总大小(类也是这样算) 结构体的特性 1.结构体(struct)是由一系列具有相同类型或不 ...
- PC逆向之代码还原技术,第四讲汇编中减法的代码还原
目录 PC逆向之代码还原技术,第四讲汇编中减法的代码还原 一丶汇编简介 二丶高级代码对应汇编观看. 1.代码还原解析: 三丶根据高级代码IDA反汇编的完整代码 四丶知识总结 PC逆向之代码还原技术,第 ...
随机推荐
- 《分布式Java应用之基础与实践》读书笔记二
远程调用方式就是尽可能地使系统间的通信和系统内一样,让使用者感觉调用远程同调用本地一样,但其实没没有办法做到完全透明,例如由于远程调用带来的网络问题.超时问题.序列化/反序列化问题.调式复杂的问题等. ...
- 使用RandomAccessFile在两个java进程之间传递数据
大部分情况下,我们面对在两个java进程只见传递数据的问题时,第一个想到的就是开server,然后通过socket收发消息.这方面有大量的框架可用,就不细说了.但如果两个进程是在一台机器上,那么还可以 ...
- 好久没发贴了,最近捣鼓了个基于node的图片压缩小网站解析。
看了下,距离上次发帖都是去年10月份的事,忙于工作的我很少跑博客园里面来玩了. 做这个小网站的初衷是 https://tinypng.com/ 这个网站有时候访问很慢,然后自己去研究了下图片压缩. 网 ...
- [ext4]010 磁盘布局 - 如何查找inode的磁盘位置
在linux系统中,任何一个文件,都有一个inode与其对应,也就是说,在一个文件系统中,一个文件都有唯一的ino来标示他,那么在ext4系统中,ino是如何确定的哪? 当我们新创建的文件或目录时,会 ...
- 搭建自己的Git服务器
前言: GitHub是一个免费托管开源代码的远程仓库,使用起来即方便又安全,但在国内有时访问巨慢,原因你懂得.还有一些公司和个人视源码如生命,既不想开源代码又不想给Github交保护费.这时搭建一个自 ...
- 页面性能优化的利器 — Timeline
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 陈泽钦,腾讯移动客户端工程师,目前就职于腾讯MIG移动互联网事业群,负责腾讯浏览服务TBS的X5内核业务. 1 ...
- smart beta
本文来至人大经济论坛,http://bbs.pinggu.org/thread-3151691-1-1.html 众所周知,beta在CAPM模型中衡量了相对于持有整个市场所带来的风险溢价(risk ...
- 图像转置的SSE优化(支持8位、24位、32位),提速4-6倍。
一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...
- 关于echarts的那些事(地图标点,折线图,饼图)
前记:离上一篇博客的发布已经过去两个月了,这期间总想写点什么,却怎么都写不出来,一直拖到了现在.现在的感觉,不是像这期间一样,想好好整理一番,写一篇好博客,却写不出来.事实发现,随心就好,较好的博客, ...
- [刷题]算法竞赛入门经典(第2版) 4-3/UVa220 - Othello
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 代码:(Accepted,0 ms) //UVa 220 - Othello #include<iostream ...