x86机器码(32位),256个字节
当我在代码页437控制台上打印代码时,看到以下内容:
j XI a I a I a jbZ Q fiQ Gf a f Q I a I a I a I a h hisZ Q I a I a I a I a hBP Z Q iQ
y Q a I a I a I a h thaZ Q I a I a I a Ih ButZ Q a I a I a I a fhu fZf Q iQ g S Q a I a I a I a hsaidZ Q I a I a I a I a hshe Z Q I a I a I a I a hAnd Z Q TZBX b
它包含一些空格字符,因此当我用替换→
所有制表符和所有不间断空格字符(使用代码255)时,这是相同的代码*
:
j XI a I a I a jbZ→Q fiQ Gf a f→Q I a I a I a I a h hisZ→Q I a I a I a I a hBP Z→Q iQ →→y →Q a I a I a I a h thaZ→Q I a I a I a Ih ButZ→Q a I a I a I a fhu fZf→Q iQ g→S →Q a I a I a I a hsaidZ→Q I a I a I a I a hshe Z→Q I a I a I a I a hAnd Z→Q TZBX*b*
十六进制转储:
6a 20 58 49 20 61 20 49 20 61 20 49 20 61 20 6a
62 5a 09 51 20 66 69 51 20 47 66 20 61 20 66 09
51 20 49 20 61 20 49 20 61 20 49 20 61 20 49 20
61 20 68 20 68 69 73 5a 09 51 20 49 20 61 20 49
20 61 20 49 20 61 20 49 20 61 20 68 42 50 20 20
5a 09 51 20 69 51 20 09 09 79 20 09 51 20 20 61
20 49 20 61 20 49 20 61 20 49 20 61 20 68 20 74
68 61 5a 09 51 20 49 20 61 20 49 20 61 20 49 20
61 20 49 68 20 42 75 74 5a 09 51 20 20 61 20 49
20 61 20 49 20 61 20 49 20 61 20 66 68 75 20 66
5a 66 09 51 20 69 51 20 67 09 53 20 09 51 20 20
61 20 49 20 61 20 49 20 61 20 49 20 61 20 68 73
61 69 64 5a 09 51 20 49 20 61 20 49 20 61 20 49
20 61 20 49 20 61 20 68 73 68 65 20 5a 09 51 20
49 20 61 20 49 20 61 20 49 20 61 20 49 20 61 20
68 41 6e 64 20 5a 09 51 20 54 5a 42 58 ff 62 ff
有关其工作原理的一些解释:
有用的说明是:
push imm8
,push imm16
和push imm32
,然后pop
生成常量。ah
当推入一个字节(imm8
)时,也会产生零(in )。
and [ecx+32], ah
-假设ah = 0,这会将字节设置为零。碰巧的是,输出字符串的长度为32,因此代码从头到尾填充了缓冲区。
or [ecx+32], edx
-假设输出字节设置为零,则复制edx
(4个字节)以输出。我使用dx
而不是edx
靠近缓冲区末尾的变量,因为它不应超出输出缓冲区。对代码的限制使得无法以这种方式写入单个字节!
imul edx, [ecx+32], whatever
-这是最主要的想法。有了足够的熵[ecx+32]
和任意数量的熵,它可以生成任何输出。我用它来生成2或3个字节的所需值。复杂之处在于,当将其写入输出时,它必须对OR
已有的逻辑进行逻辑处理。有时这使得必须再次将内存清零。
jmp
指令的变体用于返回。我之所以选择它,是因为它的编码是0xff
,它对应于代码页437中的不间断空格。规则有些繁琐,但是我认为该任务是不可能的...
程序集源代码以及运行它的C程序(使用Visual Studio语法):
#include <stdio.h>
__declspec(naked) void __fastcall doit(char* buf)
{
__asm {
push ' '
pop eax
dec ecx
and [ecx+32], ah // terminating 0 byte
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push 98
pop edx
or [ecx+32], edx
imul dx, [ecx+32], 26183
and [ecx+32], ah
or [ecx+32], dx // two bytes: [.']
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push 'sih '
pop edx
or [ecx+32], edx // 4 bytes: [ his]
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push 538988610
pop edx
or [ecx+32], edx
imul edx, [ecx+32], 544803081
or [ecx+32], edx // 1 junk byte and 3 good bytes: (t's)
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push 'aht '
pop edx
or [ecx+32], edx // 4 bytes: [ tha]
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
push 'tuB '
pop edx
or [ecx+32], edx // 1 junk byte and 3 good bytes: [But]
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push word ptr 8309
pop dx
or [ecx+32], dx
imul edx, [ecx+32], 542312807
or [ecx+32], edx // 1 junk byte and 3 good bytes: [, ']
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push 'dias'
pop edx
or [ecx+32], edx // 4 bytes: [said]
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push ' ehs'
pop edx
or [ecx+32], edx // 4 bytes: [she ]
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
dec ecx
and [ecx+32], ah
push ' dnA'
pop edx
or [ecx+32], edx // 4 bytes: [And ]
push esp
pop edx
inc edx
pop eax
jmp dword ptr[edx-1]
}
}
int main()
{
char buf[100];
doit(buf);
puts(buf);
}