我正在尝试将我写的汇编程序转换为无 NULL 的 shellcode。
但是,对于某些指令,我不确定该如何进行操作。
其中一些指令(使用 Intel 语法)包括:
push 0x1000
并且
mov BYTE [eax],0x31
我希望避免使用成千上万次的inc eax
指令。我在想,也许可以通过对值进行xor
操作来实现创意解决方案,对于第二个问题,也许有一个标志可以设置为只接受8位常数。
我正在尝试将我写的汇编程序转换为无 NULL 的 shellcode。
但是,对于某些指令,我不确定该如何进行操作。
其中一些指令(使用 Intel 语法)包括:
push 0x1000
并且
mov BYTE [eax],0x31
我希望避免使用成千上万次的inc eax
指令。我在想,也许可以通过对值进行xor
操作来实现创意解决方案,对于第二个问题,也许有一个标志可以设置为只接受8位常数。
push 0x1000
xor eax, eax
inc eax
shl eax, 12
push eax
mov BYTE [eax],0x31
xchg eax, ecx
mov BYTE [ecx],0x31
xchg eax, ecx
如果你想在内存中创建一个包含0
字节的值,你不能直接将其用作push
或mov
的立即操作数。你可以使用常量的特殊属性在寄存器中构造它,或者将其与其他内容进行异或运算。(然后使用push eax
或其他空闲寄存器)。
xor eax,eax ; 2 bytes
bts eax, 12 ; 4 bytes; eax |= 1<<12
xor eax,eax ; 2 bytes
mov ah, 0x10 ; 2 bytes; eax = 0x10 << 8
或者将一个已经清零的寄存器 push
到栈中,并进行非零字节的存储,如果您想稍后保留清零的寄存器。 push eax
/ mov byte [esp+1], 0x10
我们不关心性能,因此部分寄存器合并不是问题,窄存储器后面重新加载双字加载时也不会出现存储转发延迟。
通过push/pop或LEA指令,可以用3个字节构建范围在[-128, +127]之间的常量。
push 12 ; 2 bytes, works for -128 .. +127
pop eax ; 1 byte
lea ecx, [eax+127] ; reg+disp8 addressing mode. ECX = 139
另请参阅{{link1:在x86 / x64机器代码中打高尔夫球的技巧}}
mov eax, 0x1000 ^ 0x55555555 ; mov eax, 0x55554555
xor eax, 0x55555555 ; cancel out the constant
由于我们使用了EAX,因此这将汇编为两个5字节的指令:
b8 55 45 55 55 mov eax,0x55554555
35 55 55 55 55 xor eax,0x55555555
68 55 45 55 55 push 0x55554555 # 0x1000 ^ 0x55555555
81 34 24 55 55 55 55 xor DWORD PTR [esp],0x55555555
不仅仅是 [eax]
,而是与 AL 或 EAX 源一起使用,或者与使用 /0
作为额外的操作码位于 /r
字段中的立即指令。
mov r/m8, imm8
(C6 /0 ib
) 就是这样一条指令,因此您不能将其与普通的 [eax]
寻址模式一起使用。如果您可以偏移地址,例如 inc eax
/ [eax-1]
,那么可以使用它。
如果可以,请首先使用其他寄存器作为地址,否则有各种方法可以解决
c6 00 31 mov BYTE PTR [eax],0x31 # nope, ModRM=00
b1 31 mov cl,0x31 # using another register for data
88 08 mov BYTE PTR [eax],cl # /r field = 1 for the CL source
80 20 31 and BYTE PTR [eax],0x31 # clear bits we don't want
80 08 31 or BYTE PTR [eax],0x31 # set bits we do want
# use a different register temporarily as @user200783 suggested
91 xchg ecx,eax
c6 01 31 mov BYTE PTR [ecx],0x31
91 xchg ecx,eax # presumably need to restore it, otherwise you'd have used another reg in the first place.
# offset the address.
40 inc eax
c6 40 ff 31 mov BYTE PTR [eax-0x1],0x31
# 48 dec eax # optional, if you want to restore it
几个行不通的想法:
# halve the address (if it's known to be aligned by 2):
d1 e8 shr eax,1
c6 04 00 31 mov BYTE PTR [eax+eax*1],0x31 # Nope, SIB = 00
# write more bytes: nope: mov r/m32, imm32 also has a /0 as part of the opcode
c7 00 31 11 11 11 mov DWORD PTR [eax],0x11111131