ida版本为IDA9.0
用VScode编写IDApython
- 找到这个项目IDAcode,把下来的文件加到你ida的plugins文件夹中。
- 修改idacode_utils/settings.py中的PYTHON路径为本地的python路径
- 在本地中用控制台安装依赖
python -m pip install --user debugpy tornado
- 在VScode中安装IDAcode插件
- 在VScode按CTRL+Shift+P输入”Open User Settings(JSON)”打开后添加如下代码。
"python.autoComplete.extraPaths": [
"E:\\CTFtoolsNEW\\Reverse\\IDA90\\python\\3" //你的ida库路径
],
"python.analysis.extraPaths": [
"E:\\CTFtoolsNEW\\Reverse\\IDA90\\python\\3" //你的ida库路径
],
- 在VScode按CTRL+Shift+P,搜索ida即可找到想要的功能。
- 在ida插件中打开idacode,显示Listening on 127.0.0.1:7065即成功。
- 如果出现找不到依赖的报错,请在ida目录下找到并运行idapyswitch.exe,选择同样的python解释器(切换解释器可能会导致库的缺失,请自行安装缺失的库)。
- 如果写的命令发到ida执行报错,请在VScode中选择同样的python解释器,不要用虚拟解释器。
花指令混淆以及原理
插入操作码
常见的花指令字节码
9A:CALL immed32
E8:CALL immed16
E9:JMP immed16
EB:JMP immed8
21:add
add esp,1; 对esp进行操作
必定跳转
cpu的指令集规定了许多汇编指令,如0XE8表示的是call这个指令,并规定后面的几个字节是call的参数(跳转的地址)。
IDA通过线性扫描从开始到结尾把每一个字节反汇编成汇编指令,例如IDA识别到了一个字节0xE8(0xE8不属于前一条汇编的参数里),那么就把这个字节汇编成call,并把后面的字节识别成参数,然后继续往下分析。
那么我们是不是可以在程序中插入一个0xE8来干扰IDA的解析呢。很明显是可以的,这就是花指令的一种实现方法。如下程序中我们用_asm{}插入一段汇编代码,并用_emit插入一个0xE8的字节码。
__asm{
jz start;
jnz start;
_emit 0xE8;
}
start:
printf("yes");
在上面的代码中,因为jz与jnz都是跳转到start所以程序本身就不会执行到0xE8这个位置,但是在IDA反汇编时却会被扫描出来,从而导致把我们的0xE8识别成call,把后面的字节码识别成参数,就会导致接下来的分析错误。那么构建一个花指令其实就是想帮法构建一段内联汇编,并插入一些不会被程序执行汇编指令字节码。
有时候跳转会有很多次,有较多的花指令。
通过xor eax, eax;得到结果为0,从而使zf标志为1,造成jz必然跳转。
int main()
{
_asm {
xor eax, eax;// eax ^ eax = 0
jz s; // 必然成立跳转,一定会跳转
add esp,1;
_emit 0x22;
_emit 0x33;
s:
}
printf("test \n");
}
jmp跳转
$+5表示跳到当前地址后偏移5的位置
int main()
{
_asm {
jmp $+5
_emit 0x71
_emit 2
_emit 0xE9
_emit 0xED
}
lable:
printf("ok2");
return 0;
}
解决方法:找到垃圾代码按U然后nop掉,再按C,最后再在函数开头按P创建函数。
操作栈
栈的操作是需要平衡的,一个入栈后面必要一个出栈平衡,但是如果我们不用pop出栈,那么IDA可能就会识别到栈的不平衡而无法反编译。
不执行的栈操作
在下面的代码中我们插入了对栈顶进行操作的操作码,实际上因为永恒跳转的原因,这个操作是不会执行的,但是如果被ida识别到,那么就会认为栈是不平衡的,从而导致上面的问题。
int main() {
int main()
{
_asm {
xor eax, eax;// eax ^ eax = 0
jz s; // 必然成立跳转,一定会跳转
add esp,0x100; //操作栈顶指针,实际上不会执行
_emit 0x22;
_emit 0x33;
s:
}
printf("test \n");
}
start:
printf("hello world");
}
我们在option中的general中右上角勾选Starck pointer和设置number of byte 为8。来显示字节码和栈指针以便我们分析。
我们可以轻易发现我们写的花指令,发现ida已经识别到了栈顶指针的异常,这个时候我们只要把add的那个操作码nop掉就行。
会执行的栈操作
在下面的代码中我们push了寄存器eax,这回让esp-4然后再把eax的值放入esp指向的地址中,正常来说,我们在后面要pop eax(把esp指向地址的值赋值给eax再把esp+4)来平衡栈,但是我们这里直接用mov来操作esp来平衡,这就会导致ida识别到栈不平衡的问题。
int main() {
__asm {
push eax;
add esp, 4;
}
start:
printf("hello world");
}
这个花指令在高版本的IDA(IDA9)中好像已经不管用了,如果有这种花指令的话直接nop就行。
CALL/RET跳转
call在执行时会把返回地址入栈,并跳转到函数执行,但是如果在后面的过程中修改这个返回地址,那么当ret返回的时候就会跳转到其他的方执行。如下代码实现了这种效果,这会增加我们的分析难度,但本质还是跳转,nop掉垃圾数据就行。可以直接把call和ret部分全nop掉。
__asm {
call a;
_emit 0xE8;
a:
add dword ptr ss:[esp], 0x1; //表示以四字节(dword)写入栈段(ss)到esp指向的值(ptr表示把后面的数当成指针使用)
ret;