0.这个汇编器有什么用处???
这个汇编器是在壳内使用的汇编器,一共可以汇编47条常用指令。一般来说如果用汇编写程序也很难使用这47条指令以外的指令。这个汇编器不是让人使用的。而是让壳使用的,写过病毒或者壳的朋友一定有编写过随机花指令的经验。无非是靠模板和寄存器变换已经常数变换来生成花指令。这种花指令严重太过于依赖于模板。例如在变形引擎构建一文中列出的花指令产生函数。
如果有病毒或者壳内部带一个小型的汇编器可以让花指令玩出很多花样。
这里我也不YY一个汇编器对于构造花指令的好处了。
1.相关原理
在编译原理中有两个重要的步骤:1.词法分析。2.语法分析。词法分析函数将源文件的符号转换成词法标记。语法分析使用这些标记进行语义处理。因为这个汇编器是给壳使用的。所以当然不需要第一个步骤(词法分析)。我们的目的在于使用一个巧妙的组合算法(数学公式的随机,线性代数,图论),再加上一些函数的相互嵌套。自动生成一套用于语法分析的词法标记集合。让壳自己写程序。这样想法不错吧。呵呵。。。 这样生成的花指令和真实指令无异。。。而且随机率也更大。有兴趣的朋友可以用数学公式生产花指令一文与此文给出的代码结合。产生出自己的随机花指令构建器。
壳汇编器直接对这个词法集合进行汇编。
我先介绍一下这套汇编语言中的使用规则吧。
代码:
// 汇编标记 typedef enum _ASM_TOKEN { ASMER_TK_ERROR, /* 指令 */ ASMER_TK_INST_NOP, ASMER_TK_INST_ADD, ASMER_TK_INST_SUB, ASMER_TK_INST_MUL, ASMER_TK_INST_IMUL, ASMER_TK_INST_DIV, ASMER_TK_INST_IDIV, ASMER_TK_INST_NOT, ASMER_TK_INST_AND, ASMER_TK_INST_OR, ASMER_TK_INST_XOR, ASMER_TK_INST_SHL, ASMER_TK_INST_SHR, ASMER_TK_INST_ROL, ASMER_TK_INST_ROR, ASMER_TK_INST_MOV, ASMER_TK_INST_LEA, ASMER_TK_INST_STOSB, ASMER_TK_INST_STOSW, ASMER_TK_INST_STOSD, ASMER_TK_INST_LODSB, ASMER_TK_INST_LODSW, ASMER_TK_INST_LODSD, ASMER_TK_INST_MOVSB, ASMER_TK_INST_MOVSW, ASMER_TK_INST_MOVSD, ASMER_TK_INST_CLD, ASMER_TK_INST_STD, ASMER_TK_INST_PUSH, ASMER_TK_INST_POP, ASMER_TK_INST_PUSHAD, ASMER_TK_INST_POPAD, ASMER_TK_INST_PUSHFD, ASMER_TK_INST_POPFD, ASMER_TK_INST_RET, ASMER_TK_INST_RETN, ASMER_TK_INST_JMP, ASMER_TK_INST_CALL, ASMER_TK_INST_LOOP, ASMER_TK_INST_JZ, ASMER_TK_INST_JNZ, ASMER_TK_INST_JA, ASMER_TK_INST_JB, ASMER_TK_INST_JAE, ASMER_TK_INST_JBE, ASMER_TK_INST_CMP, ASMER_TK_INST_TEST, /* 寄存器 */ /* 8Bits 寄存器 */ ASMER_TK_REG_AL, ASMER_TK_REG_AH, ASMER_TK_REG_CL, ASMER_TK_REG_CH, ASMER_TK_REG_DL, ASMER_TK_REG_DH, ASMER_TK_REG_BL, ASMER_TK_REG_BH, /* 16Bits 寄存器 */ ASMER_TK_REG_AX, ASMER_TK_REG_CX, ASMER_TK_REG_DX, ASMER_TK_REG_BX, ASMER_TK_REG_SP, ASMER_TK_REG_BP, ASMER_TK_REG_SI, ASMER_TK_REG_DI, /* 32Bits 寄存器 */ ASMER_TK_REG_EAX, ASMER_TK_REG_ECX, ASMER_TK_REG_EDX, ASMER_TK_REG_EBX, ASMER_TK_REG_ESP, ASMER_TK_REG_EBP, ASMER_TK_REG_ESI, ASMER_TK_REG_EDI, /* 关键字 */ ASMER_TK_KW_BYTE_PTR, ASMER_TK_KW_WORD_PTR, ASMER_TK_KW_DWORD_PTR, ASMER_TK_KW_SCALE_1, ASMER_TK_KW_SCALE_2, ASMER_TK_KW_SCALE_4, ASMER_TK_KW_SCALE_8, ASMER_TK_KW_ADD, ASMER_TK_KW_SUB,/* 减号在编译的过程中换算为加号 */ ASMER_TK_KW_ADDR_LAB, ASMER_TK_KW_ADDR_VALUE_LAB, ASMER_TK_KW_DISPLACEMENT8, ASMER_TK_KW_DISPLACEMENT32, ASMER_TK_KW_IMMEDIATE8, ASMER_TK_KW_IMMEDIATE16, ASMER_TK_KW_IMMEDIATE32, ASMER_TK_KW_MEMEND, ASMER_TK_KW_LINEND, /* 结束符 */ ASMER_TK_END } ASM_TOKEN, *PASM_TOKEN;
最前面的是指令。这个不用介绍了。主要是关键字部分。
ASMER_TK_KW_BYTE_PTR, ASMER_TK_KW_WORD_PTR,ASMER_TK_KW_DWORD_PTR.这几个是指针操作符。
用于设定如 mov eax, dword ptr [XXXX]如下操作 每当想使用一个内存的时候第一个标记必然是这个类型。
ASMER_TK_KW_SCALE_(1,2,4,8) 刻度标签 跟随在内存之后使用。如果刻度为1可以忽略不记
ASMER_TK_KW_DISPLACEMENT(8,32)用于在内存中表示偏移量。
ASMER_TK_KW_IMMEDIATE(8,16,32)用于表示常量
ASMER_TK_KW_MEMEND用于结束一个内存标记
ASMER_TK_KW_LINEND用于表示一条语句的结束
ASMER_TK_END用于表示整个源文件的结束
ASMER_TK_KW_ADDR_LAB这个是地址标签表示一个地址
ASMER_TK_KW_ADDR_VALUE_LAB这个是地址值标签,表示从这个地址中取出的值
这两个标签可以在内存指针中使用,但不可以作为偏移。也可以作为常量使用
内存指针中使用:[addr_lab]或者[addr_value_lab] 这两种都可以 但是不可以以下形式[eax+addr_lab]//错误
或者当作常数
mov eax, addr_lab(或者addr_value_lab)这种情况都是允许的。 不同的是eax最后的值一个是地址 一个是地址的值.
当然如果是流程语句例如JMP CALL Jcc这类将会转换为相对于这个目的地址的偏移。

大体上就这么多了。 在附件的代码中main.cpp里有一个使用的例子。例子的代码是我胡乱打的。只为了测试用。
2.介绍源文件

写汇编器并不复杂。只要把Modrm/SIB处理掉然后根据指令进行依次填充就OK了
这个汇编器代码里有两个主要的函数一个是Compiling 一个是Linking 其实就是做语法处理的两次遍历。我为了函数意义明确就起了这两个名字。

这里介绍一个源代码:
Assembler.h定义了所有的结构
Assembler.cpp定义了主函数和所需的辅助函数,例如最后链接后的重定位
AssemblerCompiling.cpp这里实现了对每条指令的第一次汇编也是进行语法分析的主要地方
AssemblerLinking.cpp主要将编译好后的中间结构输出为了2进制到缓存中。
AssemblerSymbolTable.cpp这里是操作符号表的函数。
liblogic是辅助的一个小型库。用到了2叉哈希树做符号表。可以直接忽略掉他
这里不贴什么代码了。有兴趣的看附件吧。

3.最后的YY
这份代码花了我整一周时间。写的乱了点,希望论坛上的朋友不要见怪。不过今天晚上测试还是没有问题得~~~。 现在是临晨5:44外面的风呼呼的。。。这是什么平安夜嘛~~~


