IDApython初步使用和花指令的初步学习
ida版本为IDA9.0
用VScode编写IDApython
- 找到这个项目IDAcode,把下来的文件加到你ida的plugins文件夹中。
- 修改idacode_utils/settings.py中的PYTHON路径为本地的python路径
- 在本地中用控制台安装依赖
1 | python -m pip install --user debugpy tornado |
- 在VScode中安装IDAcode插件
- 在VScode按CTRL+Shift+P输入”Open User Settings(JSON)”打开后添加如下代码。
1 | "python.autoComplete.extraPaths": [ |
- 在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的字节码。
1 | __asm{ |
在上面的代码中,因为jz与jnz都是跳转到start所以程序本身就不会执行到0xE8这个位置,但是在IDA反汇编时却会被扫描出来,从而导致把我们的0xE8识别成call,把后面的字节码识别成参数,就会导致接下来的分析错误。那么构建一个花指令其实就是想帮法构建一段内联汇编,并插入一些不会被程序执行汇编指令字节码。
有时候跳转会有很多次,有较多的花指令。
通过xor eax, eax;得到结果为0,从而使zf标志为1,造成jz必然跳转。
1 | int main() |
jmp跳转
$+5表示跳到当前地址后偏移5的位置
1 | int main() |
解决方法:找到垃圾代码按U然后nop掉,再按C,最后再在函数开头按P创建函数。
操作栈
栈的操作是需要平衡的,一个入栈后面必要一个出栈平衡,但是如果我们不用pop出栈,那么IDA可能就会识别到栈的不平衡而无法反编译。
不执行的栈操作
在下面的代码中我们插入了对栈顶进行操作的操作码,实际上因为永恒跳转的原因,这个操作是不会执行的,但是如果被ida识别到,那么就会认为栈是不平衡的,从而导致上面的问题。
1 | int main() { |
我们在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识别到栈不平衡的问题。
1 | int main() { |
这个花指令在高版本的IDA(IDA9)中好像已经不管用了,如果有这种花指令的话直接nop就行。
CALL/RET跳转
call在执行时会把返回地址入栈,并跳转到函数执行,但是如果在后面的过程中修改这个返回地址,那么当ret返回的时候就会跳转到其他的方执行。如下代码实现了这种效果,这会增加我们的分析难度,但本质还是跳转,nop掉垃圾数据就行。可以直接把call和ret部分全nop掉。
1 | __asm { |