上一篇文章介绍了x64架构的程序通过patch让IDA无法正确识别参数的小技巧,本文补充一下x86架构中这个技巧的运用
平级函数的修改源码、编译 测试程序源码如下:
vuln只是命名习惯了...并不是指漏洞函数
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int func(int a) {
int num = a;
printf("%d",a);
getchar();
getchar();
return 1;
}
int func_wrapper(int b) {
func(b+1);
int num = b;
printf("%d",num);
getchar();
getchar();
getchar();
return 2;
}
int vuln(int num){
printf("%d",num);
return 0xff;
}
int main(int argc, char** argv) {
func_wrapper(1);
vuln(2);
return 0;
}
程序没有什么特别的,注意getchar()因为没有参数,就是用来nop掉然后开始表演的,也不会影响堆栈平衡
编译:gcc -m32 main.c -o test
编译过后IDA打开,基本是这样
混淆IDA F5的一个小技巧-x86
因为没有开优化,所以esp的加加减减没有被合并
patch 因为x64是fastcall,前几个参数用寄存器传参;而x86则全是用栈传参
原先vuln函数显示是这样的(这两个就是"平级函数")
混淆IDA F5的一个小技巧-x86
目的是让它显示成vuln(v3)这种形式,以达到一些干扰的效果
我们关注这段汇编
混淆IDA F5的一个小技巧-x86
func_wrapper的参数是1,被push到栈中
而vuln函数调用之前先收回了原先参数1的栈,又压入了自己的参数2
我们可以把vuln的参数改成1,比如这样
去掉了一个push 2,对应的,多sub esp,4
混淆IDA F5的一个小技巧-x86
保存patch版本,重新打开
显示已经变成了这样
混淆IDA F5的一个小技巧-x86
在gdb-peda中调试一下,原先可以显示出Guessed arguments
混淆IDA F5的一个小技巧-x86
现在虽然栈上的参数被我们改成了1,但也只是改了一个数值,而Guessed arguments已经显示错误了
混淆IDA F5的一个小技巧-x86
子函数改父函数 很显然刚刚的技巧在动态调试时会暴露无遗,IDA F5虽然没有成功识别参数,但是也给出了程序的大致逻辑,这次我们用一些更复杂的方法来混淆干扰
源码、编译#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int func() {
getchar();
getchar();
getchar();
return 1;
}
int func_wrapper(int num) {
printf("%d",num);
func();
printf("%d",num);
return 2;
}
int main(int argc, char** argv) {
func_wrapper(1);
return 0;
}
编译:gcc -m32 main.c -o test
我们的目标是让func_wrapper中的两次printf("%d",num);输出不同的值
patch1 关键的patch在func()里,预留的3个getchar()就是nop后留下空间表演的
混淆IDA F5的一个小技巧-x86
patch2 我们调试一下,看看nop时的esp的值,再根据func_wrapper的参数在栈上的地址,算出偏移
断在printf("%d",num);参数入栈前,发现0xffffcfd0处为参数
混淆IDA F5的一个小技巧-x86
跟进,进入func()的一堆nop中
此时esp的值0xffffcfb0为
混淆IDA F5的一个小技巧-x86
算出esp距离父函数的参数偏移为0x20
patch3 我们在func中修改如下
混淆IDA F5的一个小技巧-x86
中间改掉的三行就是把父函数printf的参数改掉了
原先运行会输出两个1,但是由于我们把第二次输出的参数改成了2,输出如下
混淆IDA F5的一个小技巧-x86
中途调的时候有好多小问题...
此时,IDA打开,func函数已经无法F5了
在func_wrapper中也看不出我们在func里做了什么手脚
混淆IDA F5的一个小技巧-x86
总结 原理不难理解,实际上手作为花指令单靠patch显然效率太低也容易被发现
上次x64的技巧,我夜影大哥给了一个C语言内联汇编在复杂函数中悄咪咪内联传参的建议,之后会试一下
另外,考虑递归函数,如果也在内层把外层的参数改了,可能会让人疯掉...没有敢去尝试
比如用一个随机数函数,加上内联汇编,符合某条件就改外层参数,栈回溯时会非常复杂
|