最近在一个壳里发现用int 2ch来反单步,第一次见到,就拿来和大家讨论一下。
当用od等调试器单步跟踪时,遇到int 2ch指令,就会跳过它下一个字节的指令,这里只是在od上看到是跳过,但它没有跳过,而且有的寄存器会改变。尤其是edx这个寄存器,不是单步的话就会变成int 2c下一条指令的地址。如果是单步跟的话,edx就回事ffffffff。为什么呢?
lkd> !idt 2c
Dumping IDT:
2c: 80541ed0 nt!KiSetLowWaitHighThread
原来int 2ch是指向nt!KiSetLowWaitHighThread
在nt!KiSetLowWaitHighThread里没有单步时候
8053d90d f644240901 test byte ptr [esp+9],1 判断
8053d912 75f8 jne nt!KiSystemCallExit (8053d90c)
8053d914 5a pop edx
8053d915 83c404 add esp,4
8053d918 80642401fd and byte ptr [esp+1],0FDh
8053d91d 9d popfd
8053d91e 59 pop ecx
8053d91f fb sti
8053d920 0f35 sysexit
如果有单步的话
8053d90d f644240901 test byte ptr [esp+9],1
8053d912 75f8 jne nt!KiSystemCallExit (8053d90c)
8053d90c cf iretd
用sysexit退出,在 Ring0 代码执行完毕,调用 SYSEXIT 指令退回 Ring3 时,CPU 会做出如下操作:
1. 将 SYSENTER_CS_MSR 的值加 16(Ring3 的代码段描述符)装载到 cs 寄存器
2. 将寄存器 edx 的值装载到 eip 寄存器
3. 将 SYSENTER_CS_MSR 的值加 24(Ring3 的堆栈段描述符)装载到 ss 寄存器
4. 将寄存器 ecx 的值装载到 esp 寄存器
5. 将特权级切换到 Ring3
6. 继续执行 Ring3 的代码
所以执行完int 2ch后至少edx,和ecx会改变。
但这里还是有一点不明白,就是byte ptr [esp+9]里面的数,不清楚这里是什么数据,为什么单步会影响到这里???????????
ps:int 2ch不知道在别的系统版本里是什么请扩,不过至少可以在xp 下能重定位,这样又比那个最经典的call pop省去4个字节。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)