汇编技巧 1
技巧1: 得到当前指令地址,花指令添加
{
__asm
{
call get_next_addr ; 得到 下一条 jmp eax 地址, 保存在 eax 中
jmp eax ; 本地跳转 , 死循环, 等待改正为 0x90,0x90 nop
mov eax, 0x1
jmp Quit
__emit 0x12 ; 无用数据 花指令
__emit 0x34
__emit 0xFF
__emit 0x4F
__emit 0xD3
__emit 0xE3
__emit 0x67
__emit 0x12
__emit 0x89
__emit 0x00
get_next_addr:
pop eax
push eax
ret
Quit:
jmp goThis ;
}
}
goThis:
printf("hello world!");
技巧2: 简单的花指令添加
花指令的出现:
汇编语言其实就是机器指令的符号化,从某种程度上看,它只是更容易理解一点的机器指令而已。每一条汇编语句,在汇编时,都会根据 CPU 特定的指令符号表将汇编指令翻译成二进制代码。而应用中,我们通过 VC 的IDE或其它如OD等反汇编、反编译软件也可以将一个二进制程序反汇编成汇编代码。
机器的一般格式为:指令+数据。
而反汇编的大致过程是:首先会确定指令开始的首地址,然后根据这个指令字判断是哪个汇编语句,然后再将后面的数据反汇编出来。
由此,我们可以看到,在这一步的反汇编过程中存在漏洞:如果有人故意将错误的机器指令放在了错误的位置,那反汇编时,就有可能连同后面的数据一起错误地反汇编出来,这样,我们看到的就可能是一个错误的反汇编代码。
这就是“花指令”,简而言之,花指令是利用了反汇编时单纯根据机器指令字来决定反汇编结果的漏洞。
thunkcode : 添加的无用数据(用 __emit )
--------------------------------------
实例 1:
call label_1
db thunkcode
jmp label_2
db thunkcode
label_1:
pop eax ;取得 label_1 的返回地址存储到 EAX, 恢复堆栈(下面语句没有用RET ,所以要手动 pop 恢复)
jmp label_3
db thunkcode,thunkcode,thunkcode
label_3:
inc eax ; EAX 值加 1, EAX 现在是 jmp label_2 这条指令的地址
jmp label_4
db thunkcode,thunkcode,thunkcode
label_4:
jmp eax ; 跳转到 jmp label_2 这条指令并执行
db thunkcode
label_2:
....
--------------------------------------
实例 2:
call label_1
db thunkcode,thunkcode
jmp label_4
label_1:
pop eax ; 取得 label_1 的返回地址存储到 EAX ,此处 pop 堆栈了
jmp label_2
db thunkcode,thunkcode
label_2:
add eax,2 ; EAX 值加 2, EAX 现在是 jmp label_4 这条指令的地址
jmp label_3
db thunkcode
label_3:
push eax ; 把 label_1 的返回地址(jmp label_4 这条指令的地址)压栈, 由 ret 指令负责弹栈返回(这里因为用了 ret , 所以应该保证栈的完好性)
ret ; 返回到 jmp label_4 指令的地址去执行
db thunkcode
label_4: ....