法医秦明有声小说顺序:vx heavens

来源:百度文库 编辑:偶看新闻 时间:2024/04/30 12:40:42
明:本人既非计算机专业,也不是英语专业的学生,所以译文有什么问题,还请多多包涵。        如果有什么意见, 请发邮件给我:uoforth@yahoo.com         希望在大家的批评下,我能成长得更快些译文如下:编写一个反汇编程序—part1-v1.00.0 介绍
0.1 什么?
0.2 为什么?
0.3 怎么做?
1.0 引擎架构
2.0 指令结构
2.1 操作码
2.2 操作数
2.3 前缀
2.4 指令结构
    2.4.1 内存地址结构
2.5 指向代码的指针
2.6 标签记号
3.0 文件组织
4.0 接下来的部分要干什么呢?------------------------------------------------------------------------------
0.0 介绍
------------------------------------------------------------------------------0.1 什么?
反汇编程序是一些把指针指向汇编代码的程序(例如,它把指针从一些EXE文件指向.TEXT(.CODE)段)。然后它把它们反汇编到一些用户容易使用的结构中。一般地,汇编指令具有一不同的长度而且如果没有反汇编的话它们很难(或者说不能)控制。0.2 为什么?
   反汇编被用于多态/变形病毒中。例如,变形病毒会反汇编自己的身体(甚至包括其中的反汇编程序),然后用反汇编[分解]结构收缩/改变/膨胀指令,接着,它会把它们再次聚合,当然是它会把它们放到它想感染的那些EXE文件中。0.3 怎么做?
          我会在汇编器中写这个引擎-因为可能我们会想要把它用于一些病毒性质的东西里:)。我使用MASM-许多人说MASM是不稳定的,就像是掷骰子一样,所以他们使用NASM。我确实知道一个什么样的汇编器会比较好。我是从MASM开始学习汇编程序的,我真的很喜欢它,因为它有个强大的宏指令引擎(这个引擎我们会用来写我们的引擎)。NASM也支持宏指令-我也曾试着用过NASM几次,但是,好吧,我还是更喜欢MASM。
-----------------------------------------------------------------------------
1.0 反汇编引擎概要
-----------------------------------------------------------------------------        我也不知道怎么去写一个好的反汇编引擎:),但是我有一些代码和一些想法(当然,代码比想法要多:)),所以我想要试一试。写这样一个引擎最重要的是架构—没有架构我 们什么都完不成!所以呢,这堂“辅导课”的前几章将会只关注我们的DASM结构的理论知识。我们首先要做的就是规划我们要怎样存储被我们的引擎反汇编了的指令。我们需要一个结构,它能够容纳任何的指令,同时呢,又容易控制它。当我们去创建它时,它将会定义我们自己的“伪”汇编语言。所以,让我们跳到下面的章节吧。
-----------------------------------------------------------------------------
2.0 指令结构
-----------------------------------------------------------------------------好了,我们需要指令结构—让我们在“——instr.inc”中创建它。下面是我们
指令的身体(现在还是空的):; _instr.inc_instr struct
    ……
_instr ends
在我们的结构中最重要的部分莫过于操作码部分了。它将会定义我们的结构所要容纳指令。让我们把它设为一个字节大小—这可以让我们容纳2^8=256个不同的值(指令)。这就足够了,因为欠并不需要处理器的每一条指令都被我们的反汇编引擎识别(例如我们并不需要FPU或MMX指令集,而只需要一些最基本的)。现在我们的结构将会变成这样::_instr.inc

_instr stuct
     opcode byte ?
    …
_instr ends    2.1 操作码
现在我们要来定义一些我们的引擎将会用到的指令—让我们创建“opcodes.inc”文件(在隔离的文件写代码可以让我们更容易的来管理我们的项目 )。我们可以决定每一条指令有一个什么编码(0-255)。但是首先让我们列出那些将会在我们的引擎中用到的X86指令:
name operand1 operand2 arithmetic instructions add ; add mem/reg mem/reg/imm sub ; sub mem/reg mem/reg/imm inc ; inc mem/reg dec ; dec mem/reg neg ; neg mem/reg mul ; mul mem/reg eax/edx div ; div mem/reg eax/edx logic instructions or ; or mem/reg mem/reg/imm and ; and mem/reg mem/reg/imm xor ; and mem/reg mem/reg/imm not ; not mem/reg shift instructions shl ; shl mem/reg imm/cl shr ; shr mem/reg imm/cl sal ; sal mem/reg imm/cl sar ; sar mem/reg imm/cl rotation instructions rol ; rol mem/reg imm/cl ror ; ror mem/reg imm/cl rcl ; rcl mem/reg imm/cl rcr ; rcr mem/reg imm/cl data transfer instructions mov ; mov mem/reg mem/reg/imm xchg ; xchg mem/reg mem/reg push ; push mem/reg/imm pop ; pop mem/reg pusha; pusha popa ; popa pushad;pushad popad; popad pushf; pushf pushfd;pushfd popf ; popf popfd; popfd stc ; stc clc ; stc cmc ; stc std ; stc cld ; stc sti ; stc cli ; stc cbw ; stc cwd ; stc cwde ; stc other instructions lea ; lea reg mem nop ; nop program control instructions jxx ; jxx mem/reg/imm jmp ; jmp mem/reg/imm enter; enter imm imm leave;leave call; call mem/reg/imm ret ; ret imm loopxx;loopxx imm string instructions cmps; cmps esi edi lods; lods esi eax movs; movs esi edi scas; scas edi eax stos; stos edi eax compare in structions cmp ; cmp mem/reg mem/reg/imm test; test mem/reg mem/reg/imm virtual instructions movm; movm mem mem apistart; imm apiend; imm imm
好了,这个表格需要解释一下。它包括了在我们的引擎中需要的所有指令—当然我们可以在这里放任何指令,但是大部分我们可能都不会用。虚拟指令—这是什么?在汇编程序中,没有像mov mem,mem这样的指令—这是不允许的。但是我们在程序中却必须经常这样做。我们用像push mem/pop mem或mov reg,mem/mov mem,reg…这样来实现它。但是在我们的伪汇编程序中我们可以把这些指令链接到一条movm(mov mem to mem)指令.在后面它可以帮助我们来控制代码。我们只需在汇编过程中将它膨胀为两条指令就行了。apistart/apiend只是程序的序幕(push ebp/mov ebp,esp/sub esp,imm)和尾声(add esp,imm/pop ebp).如果表格中的指令你都不懂,在google中输入"intel instruction set"(INTEL 指令设置),然后查看开关的那几个链接来获得指令及它们解释。关于操作数有些很重要的东西—即使操作数1可以为内存且操作数2也可以为内存—不要忘了mem,mem是不允许的!好吧,那么操作数的大小呢?显然,寄存器操作数可以为8/16/32位。并且,立即数也可以是8/16/32位。但是我们的伪汇编程序必须尽可能让我们觉得舒服,所以接下来我们将会在结构中包含操作数大小的信息。现在有一条条指令,让我们来创建“opcode.inc”,在这里我们将会声明一些常量。; opcodes.inc
.const
; arithmetic instructions
OPCODE_ADD equ 000h
OPCODE_SUB equ 001h
OPCODE_INC equ 002h
OPCODE_DEC equ 003h
OPCODE_NEG equ 004h
OPCODE_MUL equ 005h
OPCODE_DIV equ 006h

; logic instructions
OPCODE_OR equ 007h
OPCODE_AND equ 008h
OPCODE_XOR equ 009h
OPCODE_NOT equ 00ah

; shift instructions
OPCODE_SHL equ 00bh
OPCODE_SHR equ 00ch
OPCODE_SAL equ 00dh
OPCODE_SAR equ 00eh

; rotation instructions
OPCODE_ROL equ 00fh
OPCODE_ROR equ 010h
OPCODE_RCL equ 011h
OPCODE_RCR equ 012h

; data transfer instructions
OPCODE_MOV equ 013h
OPCODE_XCHG equ 014h
OPCODE_PUSH equ 015h
OPCODE_POP equ 016h
OPCODE_PUSHA equ 017h
OPCODE_POPA equ 018h
OPCODE_PUSHAD equ 019h
OPCODE_POPAD equ 01ah
OPCODE_PUSHF equ 01bh
OPCODE_PUSHFD equ 01ch
OPCODE_POPF equ 01dh
OPCODE_POPFD equ 01eh
OPCODE_STC equ 01fh
OPCODE_CLC equ 020h
OPCODE_CMC equ 021h
OPCODE_STD equ 022h
OPCODE_CLD equ 023h
OPCODE_STI equ 024h
OPCODE_CLI equ 025h
OPCODE_CBW equ 026h
OPCODE_CWD equ 027h
OPCODE_CWDE equ 028h

; other instructions
OPCODE_LEA equ 02ah
OPCODE_NOP equ 090h

; program control instructions
OPCODE_JXX equ 02ch
OPCODE_JMP equ 02dh
OPCODE_ENTER equ 02eh
OPCODE_LEAVE equ 02fh
OPCODE_CALL equ 030h
OPCODE_RET equ 031h
OPCODE_LOOPXX equ 032h

; string instructions
OPCODE_CMPS equ 033h
OPCODE_LODS equ 034h
OPCODE_MOVS equ 035h
OPCODE_SCAS equ 036h
OPCODE_STOS equ 037h

; compare in structions
OPCODE_CMP equ 03eh
OPCODE_TEST equ 03fh

; virtual instructions
OPCODE_MOVM equ 040h
OPCODE_APISTART equ 041h
OPCODE_APIEND equ 042h
2.2 操作数
现在我们的_instr structure需要一些变量,它们将会作为[代表]我们在opcode部分中定义的指令所要使用的操作数。首先让我们来看看我们将会添加一些什么东西到“_instr.inc”文件中:; _instr.incinclude opcodes.inc
include operands.inc_instr struct
   opcode byte ?
   operands byte ?
   ...
_instr ends我们唯一需要的就是operands.inc文件!但是在我们的汇编程序中有哪几种类型的操作数呢?操作数总共有3种类型:reg(寄存器),mem(内存地址),imm(立即数-常数)。每个指令可以有0,1,2个操作数(好吧,实际上也有指令使用三个操作数,但是我们不需要它们)。所以:; _operands.inc

.const

OPERANDS_NONE equ 000h
OPERANDS_REG equ 001h
OPERANDS_MEM equ 002h
OPERANDS_IMM equ 003h
OPERANDS_REG_REG equ 004h
OPERANDS_REG_MEM equ 005h
OPERANDS_REG_IMM equ 006h
OPERANDS_MEM_MEM equ 007h
OPERANDS_MEM_REG equ 008h
OPERANDS_MEM_IMM equ 009h2.3 前缀
前缀就是我们放在指令前面的一些字节。指令可能会有0,1或更多个前缀。不是每条指令都会有固定的前缀的。这里有几组前缀: Lock and repeat prefixes (3 values): LOCK 0f0h REPNE/REPNZ 0f2h REP 0f3h REPE/REPZ 0f3h (same as REP) SIMD 0f3h (same as REP) Segment override prefixes (6 values): CS 02eh SS 036h DS 03eh ES 026h FS 064h GS 065h Operand-size override prefix (1 value): OP_SIZE 066h Address-size override prefix (1 value): ADDR_SIZE 067h 任何一条指令最多只可以拥有每组前缀中的一个—所以每条指令最多可以有4个前缀(我们有4组前缀)。有两个前缀我们是不会用到的—SIMD和LOCK—我们只是不需要它们。我们将会把所有的前缀数据储存到一个叫做prefixes的字节中:; _instr.incinclude opcodes.inc
include operands.inc
include prefixes.inc_instr struct
   opcode byte ?
   operands byte ?
   prefixes byte ?
   ...
_instr ends我们有一个字节即8位来储存这些值。让我们这样做:[7] [6] [5] [4] [3] [2] [1] [0]
      \ | / | | | |_ operand size (bit 0)
       \ | / | | |_ address size (bit 1)
        \|/   | |_ REPNE/REPNZ (bit 2)
         |    |_ REP/REPE/REPZ (bit 3)
         |_ segment override (bit 4,5,6)第7位我们现在不会用到,可能在后面我们会用它来储存一些额外的数据。好了,让我们来看一看“prefixes.inc”:; prefixes.inc

.const

; bit patterns
PREFIX_OP_SIZE equ 01h ; bit 0 PREFIX_ADDR_SIZE equ 02h ; bit 1
PREFIX_REPNE equ 04h ; bit 2
PREFIX_REPNZ equ PREFIX_REPNE
PREFIX_REPE equ 08h ; bit 3
PREFIX_REP equ PREFIX_REPE
PREFIX_REPZ equ PREFIX_REPE
PREFIX_SEG_NONE equ 0 000 0000b
PREFIX_CS equ 0 001 0000b
PREFIX_SS equ 0 010 0000b
PREFIX_DS equ 0 011 0000b
PREFIX_ES equ 0 100 0000b
PREFIX_FS equ 0 101 0000b
PREFIX_GS equ 0 110 0000b

; bit indexes (only for 1 bit prefixes)
BI_OP_SIZE equ 00h
BI_ADDR_SIZE equ 01h
BI_REPNE                          equ 02h
BI_REPNZ              equ BI_REPNE
BI_REPE equ 03h
BI_REP equ BI_REPE
BI_REPZ equ BI_REPE

; prefix real opcodes
OPCODE_OP_SIZE equ 066h
OPCODE_ADDR_SIZE equ 067h
OPCODE_REPNE equ 0f2h
OPCODE_REPNZ equ OPCODE_REPNE
OPCODE_REPE equ 0f3h
OPCODE_REP equ OPCODE_REPE
OPCODE_REPZ equ OPCODE_REPE
OPCODE_CS equ 02eh
OPCODE_SS equ 036h
OPCODE_DS equ 03eh
OPCODE_ES equ 026h
OPCODE_FS equ 064h
OPCODE_GS equ 065h2.4 指令数据
我们已经用操作码,操作数和前缀定义了我们的结构,现在我们要来创建一些结构来容纳指令数据了—例如它用的是哪个寄存器,内存地址,任何立即数等。这个结构的使用将会依赖它是哪条指令,它用什么操作数和它有什么前缀(专门的操作数和地址前缀)。让我们来看看这个结构(“_idata.inc”):
; _idata.incinclude registers.inc
include _mem.inc_idata struct
   union
    reg1 byte ?
    union
     imm1_8 byte ?
     imm1_16 word ?
     imm1_32 dword ?
    ends
    mem1 _mem <>
   ends
   union
    reg2 byte ?
    union
     imm2_8 byte ?
     imm2_16 word ?
     imm2_32 dword ?
    ends
    mem2 _mem <>
   ends
ends好了,我们有2个共用体在里面—我们可以用任一个作为寄存器/立即数/内存。它使我们可以从已定义的OPERANDS_XXX常数中创建任何选项。reg1和reg2当然会用来编码寄存器。我们需要一些常数(“register.inc”):
; registers.inc.const   REG_EAX equ 00h
   REG_EBX equ 03h
   REG_ECX equ 01h
   REG_EDX equ 02h
   REG_ESI equ 06h
   REG_EDI equ 07h
   REG_EBP equ 05h
   REG_ESP equ 04h2.4.3 内存地址结构

我们有一些X86处理器寻址模式。例如我们有直接地址[0x00112233]或寄存器[eax]等等。最复杂的可能是像这样的寻址方式[reg1+reg2*乘数+偏移量](在下面的章节我们将会把焦点放在特定的寻址模式)。乘数可以是1/2/4/8。它只有4个值所以我们只需要2位来编码它们。接下来偏移量——它可以是1/2/4/字节长,所以我们需要4个字节来编码它。所以我们的_mem struct将会像这样(“_mem,inc”):; _mem.incinclude registers.inc.const
   ; multiplication values
   MULTI_1 equ 00 000000b
   MULTI_2 equ 01 000000b
   MULTI_4 equ 10 000000b
   MULTI_8 equ 11 000000b   MULTI_BITMASK equ 11 000000b   ; addressing modes
   MODE_DISP    equ 100 00000b
   MODE_REG    equ 011 00000b
   MODE_REG_REG    equ 010 00000b
   MODE_REG_DISP    equ 001 00000b
   MODE_REG_REG_DISP equ 000 00000b   MODE_BITMASK   equ 111 00000b_mem struct
   memreg1 byte ? ; bits 5/6/7 = mode
   memreg2 byte ? ; bits 6/7 = multiplicator
   union
    disp8 byte ?
    disp16 word ?
    disp32 dword ?
   ends
_mem ends所以在memreg1字节里,0/1/2位包含寄存器的信息,5/6/7位包含寻址模式的信息。在memreg2字节里0/1/2位编码第2个寄存器,6/7位定义乘数。DISP共用体只仅仅只是过滤[displacement]哪些可以为1/2/4个字节宽。2.5 指向代码的指针
_instr structure的下一个成员将会是指向代码的指针—它将只指向我们要反汇编的真实代码—它非常的重要,但是在后面我会解释。
所以这个指针将只是个双字且我们将把它称作"pointer"(指针)—看一下2.6节来了解整个_instr structurer的定义。2.6 “标签记号”

标签记号是Mental Driller(我是这样认为的)在他的叫做“metamorpho”的变形病毒中“发明”的一个非常得心应手的东西。在反汇编中它并不是必须的,但是它在变体代码时会很重要。标签记号只是可以为0或1的一个字节。如果有jump/call指向这条指令(指令对它有一个标签)时它为1,或者如果没有的话,它为0。整个_instr structure现在像这样:; _instr.incinclude opcodes.inc
include operands.inc
include prefixes.inc
include _idata.inc_instr struct
   opcode byte ?
   operands byte ?
   prefixes byte ?
   _idata idata <>
   pointer dword ?
   labelmark byte ?
_instr ends------------------------------------------------------------------------------
3.0 文件组织
------------------------------------------------------------------------------

好了,我们创建了一些文件—现在让我们整体的看一看我们要怎么来设定我们的引擎的目录。首先我们需要一个根目录—让我们把它称为“dasm_engine”。在里面欠有两个文件夹“source”和“include”或者如果你想的话也可以是“src”和“inc”(我选择了src/inc)。我们要把所有的*.inc文件放在“inc”目录里然后把所有*.asm文件放到“src“目录中。所以到现在为止我们有:> dasm_engine
     > src
     > inc
         > _instr.inc
   > opcodes.inc
   > operands.inc
   > prefixes.inc
   > registers.inc
   > _mem.inc
   > _idata.inc你可以从这个链接下载这些文件:
http://vx.netlux.org/lib/files/vmd/dasm_engine.rar
------------------------------------------------------------------------------
4.0 接下来的部分要干什么呢?
------------------------------------------------------------------------------在下面的部分我们会讨论整个引擎惯例—它怎么工作的,它会有哪些参数等等。然后我们会写一些(或者很多:))有用的宏指令。并且我们会开始来写反汇编的程序了:).如果你有任何问题或者评论或者任何其他的事请给我发邮件:
alek.barszczewski@gmail.com后记:看来这编文章是还没完,如果有更新,我可能会把文章译完,就当是把它看完,因为这编文章真的很不错。不过即使没有了后面,我想他的思想我们是能够把握住了,这也就差不多了,是不是。如果真的要研究反汇编程序,可以去网络上下载HDE参考。OK,就到这了。新手上道,还请多多教导