您好,欢迎来到99网。
搜索
您的当前位置:首页REVERSE总结

REVERSE总结

来源:99网

1.ARM汇编指令

1)ARM指令通常跟一到两个操作数,我们使用如下模板描述:

MNEMONIC{S}{condition} {Rd}, Operand1, Operand2

其中各个字段的作用如下:

MNEMONIC - 指令的助记符如ADD

{S} - 可选的扩展位,如果指令后加了S,将依据计算结果更新CPSR寄存器中相应的FLAG

{condition} - 执行条件,如果没有指定,默认为AL(无条件执行)

{Rd} - 目的寄存器,存储指令计算结果

Operand1 - 第一个操作数,可以是一个寄存器或一个立即数

Operand2 - 第二个(可变)操作数,可以是一个立即数或寄存器甚至带移位操作的寄存器

助记符、S扩展位、目的寄存器和第一个操作数的作用很好理解,不多做解释,这里补充解释一下执行条件和第二个操作数。设置了执行条件的指令在执行指令前先校验CPSR寄存器中的标志位,只有标志位的组合匹配所设置的执行条件指令才会被执行。第二个操作数被称为可变操作数,因为它可以被设置为多种形式,包括立即数、寄存器、带移位操作的寄存器,如下所示:
#123 - 立即数

Rx - 寄存器比如R1

Rx, ASR n - 对寄存器中的值进行算术右移n位后的值

Rx, LSL n - 对寄存器中的值进行逻辑左移n位后的值

Rx, LSR n - 对寄存器中的值进行逻辑右移n位后的值

Rx, ROR n - 对寄存器中的值进行循环右移n位后的值

Rx, RRX - 对寄存器中的值进行带扩展的循环右移1位后的值

1.1.载入和存储

ldr = Load Word 载入字

ldrh = Load unsigned Half Word 载入无符号半字

ldrsh = Load signed Half Word 载入有符号半字

ldrb = Load unsigned Byte 载入无符号字节

ldrsb = Load signed Bytes 载入有符号字节

str = Store Word 储存字

strh = Store unsigned Half Word 储存无符号半字

strsh = Store signed Half Word 储存有符号半字

strb = Store unsigned Byte 储存无符号字节

strsb = Store signed Byte 储存有符号字节

ldm r0, {r4,r5} /* words[3] -> r4 = 0x03; words[4] -> r5 = 0x04 */

使用LDM指令,将R0指向的内存中,取两个字的数据出来。由于之前我们让R0指向了word[3],因此word[3]的值会被存入R4, word[4]的会被存入R5

stm r1, {r4,r5} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04 */
使用STM指令将多个值写入内存。STM指令将R4,R5寄存器的值0x3和0x4存入R1指向的内存空间中。

LDM和STM有多种不同的使用形式。具体是哪一种使用形式由指令的后缀所决定。这个示例列出了后缀的几种形式:-IA (之后增加), -IB (之前增加), -DA (之后减少), -DB (之前减少)。

ldmia r0, {r4-r6} /* words[3] -> r4 = 0x03, words[4] -> r5 = 0x04; words[5] -> r6 = 0x05; */

stmia r1, {r4-r6} /* r4 -> array_buff[0] = 0x03; r5 -> array_buff[1] = 0x04; r6 -> array_buff[2] = 0x05 */

ldmib r0,{r4-r6} /*words[4] -> r4 = 0x04; words[5] -> r5 = 0x05; words[6] -> r6 = 0x06 */

stmib r1,{r4-r6} /* r4-> array_buff[1] = 0x04; r5 -> array_buff[2] = 0x05; r6 ->array_buff[3] = 0x06 */

ldmda r0, {r4-r6} /* words[3] -> r6 = 0x03; words[2] -> r5 = 0x02; words[1] -> r4 = 0x01 */

使用LDMDA向相反方向执行运算。

stmda r2, {r4-r6} /* r6 -> array_buff[2] = 0x02; r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00 */

同样的道理

stmdb r2, {r4-r5} /* r5 -> array_buff[1] = 0x01; r4 -> array_buff[0] = 0x00; */

1.2.转移指令

当特定条件满足时,借助条件指令, 通过跳转(分支)或执行某些特定指令来控制程序的流动方向。相关条件被描述为CPSR寄存器中的特定位的状态,这些位根据指令计算后的结果实时改变。比如,如果我们比较两个数并且他们相等,就将零标志位置位(Z=1) ,因为在系统底层发生了a-b=0。在这个例子里两个数是相等的,但如果第一个数字比第二个大,会得出大于结论。而相反的情况下得出小于结论。当然还有很多其他的条件,比如小于等于(LE),大于等于(GE)等等。

下表列出了可能的条件指令,他们的含义以及被检测的状态标志位

1.3.跳转指令

b分支指令 简单地跳向一个函数

bl分支连接指令 将(PC+4)保存到LR中并跳转到函数

BX(分支切换指令)和BLX(分支连接切换指令)

a) 和B/BL+交换指令集相同( ARM <-> Thumb )

b) 需要用寄存器作为第一操作数:BX/BLX+具体的寄存器

BX/BLX用来从ARM指令集切换到Thumb指令集

2.PE文件知识

2.1.PE头

PE头分为5个部分,如下表

在DOS-根之后是一个32位的签名以及魔数0x00004550 (IMAGE_NT_SIGNATURE)(意为“NT签名”,也就是PE签名;十六进制数45和50分别代表ASCII码字母E和P----译者注)。

之后是文件头(按COFF格式),用来说明该二进制文件将运行在何种机器之上、分几个区段、链接的时间、是可执行文件还是DLL、等等。(本文中可执行文件和DLL文件的区别在于:DLL文件不能被启动,但能被别的二进制文件使用,而一个二进制文件则不能链接到另一个可执行文件。)

2.2.PE头之IMAGE_FILE_HEADER解析

在IMAGE_DOS_HEADER结构中,只关心e_magic以及e_lfanew,分别是第一个字段以及最后一个字段。

1.e_magic字段

e_magic字段类型为WORD,占用两个字节,表示PE文件的一个Magic标志,它的值固定为4D 5A,即PE文件的e_magic值一定就是4D 5A,如果不是4D 5A则表示不是PE文件,因此e_magic通常作为识别一个文件是否是PE文件的标准之一。在小端模式下,4D 5A表示为WORD类型的数据为0x5A4D,在WinNT.h头文件中定义了一个名为IMAGE_DOS_SIGNATURE的宏,它的值就是0x5A4D,如下所示:

#define IMAGE_DOS_SIGNATURE    0x5A4D  // MZ

2.e_lfanew字段

e_lfanew用于指定PE文件头的偏移,因为在IMAGE_DOS_HEADER头和PE头之间隔了一段DosStub数据,而DosStub的大小是可变的,所以需要通过e_lfanew才能找到PE文件头的位置。IMAGE_DOS_HEADER结构体的大小为字节,而e_lfanew位于该结构的最后四字节,所以e_lfanew对应第61~四个字节的数据(下标索引为60~63)。

2.3.PE头之IMAGE_FILE_HEADER

IMAGE_NT_HEADERS结构体在WinNT.h头文件中的定义如下所示:

typedef struct _IMAGE_NT_HEADERS {

    DWORD Signature;

    IMAGE_FILE_HEADER FileHeader;

    IMAGE_OPTIONAL_HEADER32 OptionalHeader;

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

可以看出,IMAGE_NT_HEADERS由一个DWORD类型的Signature成员、一个IMAGE_FILE_HEADER类型的FileHeader、以及一个IMAGE_OPTIONAL_HEADER32类型的OptionalHeader组成。

Signature字段的类型为DWORD,占用四个字节,也表示PE文件的一个Magic标志(在之前的实验中,讲到了IMAGE_DOS_HEADER的e_magic也是PE文件的Magic标志),同样,Signature的值固定为50 45 00 00,在小端模式下表示为0x00004550,字符串表示为“PE\0\0”。Signature在WinNt.h头文件中的定义如下所示:

#define IMAGE_NT_SIGNATURE    0x00004550  // PE00

1.该结构的第二个成员为FileHeader,对应的类型为IMAGE_FILE_HEADER,该结构体在WinNt.h头文件中的定义如下:

typedef struct _IMAGE_FILE_HEADER {

    WORD    Machine;

    WORD    NumberOfSections;

    DWORD   TimeDateStamp;

    DWORD   PointerToSymbolTable;

    DWORD   NumberOfSymbols;

    WORD    SizeOfOptionalHeader;

    WORD    Characteristics;

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

2.4.PE头之IMAGE_OPTIONAL_HEADER解析

typedef struct _IMAGE_OPTIONAL_HEADER {

   WORD    Magic;

   BYTE    MajorLinkerVersion;

   BYTE    MinorLinkerVersion;

   DWORD   SizeOfCode;

   DWORD   SizeOfInitializedData;

   DWORD   SizeOfUninitializedData;

   DWORD   AddressOfEntryPoint;

   DWORD   BaseOfCode;

   DWORD   BaseOfData;

   DWORD   ImageBase;

   DWORD   SectionAlignment;

   DWORD   FileAlignment;

   WORD    MajorOperatingSystemVersion;

   WORD    MinorOperatingSystemVersion;

   WORD    MajorImageVersion;

   WORD    MinorImageVersion;

   WORD    MajorSubsystemVersion;

   WORD    MinorSubsystemVersion;

   DWORD   Win32VersionValue;

   DWORD   SizeOfImage;

   DWORD   SizeOfHeaders;

   DWORD   CheckSum;

   WORD    Subsystem;

   WORD    DllCharacteristics;

   DWORD   SizeOfStackReserve;

   DWORD   SizeOfStackCommit;

   DWORD   SizeOfHeapReserve;

   DWORD   SizeOfHeapCommit;

   DWORD   LoaderFlags;

   DWORD   NumberOfRvaAndSizes;

   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

IMAGE_OPTIONAL_HEADER结构各个成员字段的含义如下:

  1. Magic,表明是ROM映像还是普通的可执行映像,普通的可执行文件的值为0x010B,PE32+可执行文件的值为0x020B(PE32+即位的PE文件,这种文件只能运行在位的Windows操作系统下);

  2. MajorLinkerVersion,链接器的主版本号;

  3. MinorLinkerVersion,链接器的次版本号;

  4. SizeOfCode,代码区块的大小,通常而言可执行文件仅有一个代码区块.text,所以通常就是.text区块的大小;

  5. SizeOfInitializedData,已初始化数据块的大小,不作研究;

  6. SizeOfUninitializedData,未初始化数据块的大小,不作研究;

  7. SectionAlignment,当PE文件装载到内存时区块的对齐大小,假设.text区块的大小为0x7748,而SectionAlignment的大小为0x1000,那么对齐后的大小为0x8000字节;

  8. FileAlignment,磁盘上PE文件中区块的对齐大小,对齐方式类似SectionAlignment;

  9. MajorOperatingSystemVersion,要求的操作系统最低的主版本号;

  10. MinorOperatingSystemVersion,要求的操作系统最低的次版本号;

  11. MajorImageVersion,PE文件本身的主版本号;

  12. MinorImageVersion,PE文件本身的次版本号;

  13. MajorSubsystemVersion,要求的子系统最低的主版本号;

  14. MinorSubsystemVersion,要求的子系统最低的次版本号;

  15. Win32VersionValue,保留字段,通常为0;

  16. SizeOfImage,PE文件被装载到内存空间后总的大小,指从ImageBase到最后一个区块的大小;

  17. SizeOfHeaders,Dos头、DosStub、PE头以及区块头的总大小,并进行FileAlignment对齐后的大小;

  18. CheckSum,校验和,一般的EXE文件通常为0,对重要的系统驱动程序而言比较有意义;

  19. Subsystem,子系统,EXE最常用的子系统类型有console以及windows,分别对应控制台应用程序以及GUI应用程序;

  20. DllCharacteristics,包含有DEP以及ASLR相关的属性位;

  21. SizeOfStackReserve,不作研究;

  22. SizeOfStackCommit,不作研究;

  23. SizeOfHeapReserve,不作研究;

  24. SizeOfHeapCommit,不作研究;

  25. LoaderFlags,与调试相关,不作研究;

typedef struct _IMAGE_DATA_DIRECTORY {
      DWORD   VirtualAddress;
      DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

2.5.PE头之节表头解析

紧跟在IMAGE_NT_HEADERS之后的是节表头,即IMAGE_SECTION_HEADER。
每个节区都会有一个对应的节表头,节表头以及节区的数量都是由IMAGE_NT_HEADERS.FileHeader.NumberOfSections字段的值所决定的。节表头对应的结构体为IMAGE_SECTION_HEADER,该结构体在WinNT.h头文件中的定义如下所示:

typedef struct _IMAGE_SECTION_HEADER {

    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];

    union {

            DWORD   PhysicalAddress;

            DWORD   VirtualSize;

    } Misc;

    DWORD   VirtualAddress;

    DWORD   SizeOfRawData;

    DWORD   PointerToRawData;

    DWORD   PointerToRelocations;

    DWORD   PointerToLinenumbers;

    WORD    NumberOfRelocations;

    WORD    NumberOfLinenumbers;

    DWORD   Characteristics;

} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

其中各个字段的介绍如下:

  1. Name,为对应节区的名字,其中IMAGE_SIZEOF_SHORT_NAME的值固定为8。如果名字的长度小于8,则以NULL字符结束;如果名字的长度等于8,则没有NULL字符,因为数组长度为8。节区的名字通常以点号开头,如.text、.data等,通常而言,这个名字可以随便修改。

  2. VirtualSize,在未对齐的情况下,区块所有数据的大小。

  3. VirtualAddress,区块被装载到内存时的RVA,这个值总是SectionAlignment的整数倍。

  4. SizeOfRawData,区块数据在磁盘文件中按照FileAlignment对齐后的大小。

  5. PointerToRelocations、PointerToLinenumbers、NumberOfRelocations、NumberOfLinenumbers:不是很重要的字段,这里不作研究。

  6. Characteristics,区块的属性值,表明区块的可读、可写、可执行等相关属性。

2.6.输入表解析

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

    union {

         DWORD   Characteristics;

         DWORD   OriginalFirstThunk;

     } DUMMYUNIONNAME;

          DWORD   TimeDateStamp;

          DWORD   ForwarderChain;

          DWORD   Name;

          DWORD   FirstThunk;

} IMAGE_IMPORT_DESCRIPTOR;

关于IID结构体中各个成员的含义介绍如下:

  1. OriginalFirstThunk,RVA,指向输入名称表(简称INT),INT是一个类型为IMAGE_THUNK_DATA结构的数组,同样的,通过在数组末尾附加一个空的IMAGE_THUNK_DATA结构来表示数组的结束,每一个输入的函数都有一个对应的IMAGE_THUNK_DATA结构;
  2. TimeDateStamp,DLL的时间日期标志,通常忽略;
  3. ForwarderChain,通常忽略,不作讲解;
  4. Name,RVA,指向DLL的名字,如“User32.dll”;
  5. FirstThunk,RVA,指向输入地址表(简称IAT),IAT也是一个类型为IMAGE_THUNK_DATA结构的数组,同样的,通过在数组末尾附加一个空的IMAGE_THUNK_DATA结构来表示数组的结束,每一个输入的函数都有一个对应的IMAGE_THUNK_DATA结构;
    需要注意的是,OriginalFirstThunk与FirstThunk极其相似,前者指向INT,后者指向IAT,其中INT和IAT都是类型为IMAGE_THUNK_DATA的数组

IMAGE_THUNK_DATA结构:

typedef struct _IMAGE_THUNK_DATA32 {

     union {

         DWORD ForwarderString;

         DWORD Function;

         DWORD Ordinal;

         DWORD AddressOfData;

     } u1;

} IMAGE_THUNK_DATA32;

可以看出,该类型仅有的一个成员u1是一个联合体(union),而联合体内的类型都是DWORD,所以IMAGE_THUNK_DATA的大小是4字节。当该类型的最高位为1时,表示函数以序号的方式进行输入,这时候低31位的值就表示函数的序号;当该类型的最高位为0时,表示函数以名字的方式进行输入,这时候值就表示一个指向IMAGE_IMPORT_BY_NAME结构的RVA。

typedef struct _IMAGE_IMPORT_BY_NAME {

     WORD    Hint;

     BYTE    Name[1];

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

2.7.输出表解析

typedef struct _IMAGE_EXPORT_DIRECTORY {

    DWORD   Characteristics;

    DWORD   TimeDateStamp;

    WORD    MajorVersion;

    WORD    MinorVersion;

    DWORD   Name;

    DWORD   Base;

    DWORD   NumberOfFunctions;

    DWORD   NumberOfNames;

    DWORD   AddressOfFunctions;

    DWORD   AddressOfNames;

     DWORD   AddressOfNameOrdinals;

} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
  1. Characteristics,表示输出属性,这个值当前没有意义,总是设置为0;

  2. TimeDateStamp,输出表创建的时间(格林威治标准时间);

  3. MajorVersion,输出表的主版本号,这个值当前没有意义,总是设置为0;

  4. MinorVersion,输出表的次版本号,这个值当前没有意义,总是设置为0;

  5. Name,RVA,模块的真实名字,指向一个ASCII字符串,这个字符串是与这些输出函数关联的DLL的名字(如User32.dll);

  6. Base,输出表的起始序数值;

  7. NumberOfFunctions,输出函数的个数;

  8. NumberOfNames,以名字输出的函数的个数;

  9. AddressOfNames,RVA,指向包含以名字方式输出的函数的ASCII字符串名字的RVA数组;

  10. AddressOfNameOrdinals,RVA,指向每个以名字方式输出的函数对应在AddressOfFunctions指向的数组中的索引;

2.8.资源结构解析

typedef struct _IMAGE_RESOURCE_DIRECTORY {

    DWORD   Characteristics;

    DWORD   TimeDateStamp;

    WORD    MajorVersion;

    WORD    MinorVersion;

    WORD    NumberOfNamedEntries;

    WORD    NumberOfIdEntries;

} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

IMAGE_RESOURCE_DIRECTORY结构体中各个字段的含义如下:

  1. Characteristics,资源的属性标志,当前没有意义,它的值总是设置为0;

  2. TimeDateStamp,资源数据被资源编译器创建的时间;

  3. Major Version,资源的主版本号,通常为0;

  4. Minor Version,资源的次版本号,通常为0;

  5. NumberOfNamedEntries,重要字段,以字符串命名的资源条目的数量;

  6. NumberOfIdEntries,重要字段,以整数命名的资源条目的数量;

在IMAGE_RESOURCE_DIRECTORY之后,紧跟着NumberOfNamedEntries + NumberOfIdEntries个IMAGE_RESOURCE_DIRECTORY_ENTRY(简称IRDE)结构类型的数据。IMAGE_RESOURCE_DIRECTORY_ENTRY结构体在WinNT.h头文件中的定义如下所示:

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {

    DWORD   Name;

    DWORD   OffsetToData;

} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

该结构体占用8个字节,结构体的成员的介绍如下:

  1. Name,这个字段拥有多个不同的含义:当IRDE位于第一层目录时,Name表示资源的类型;当IRDE位于第二层目录时,Name表示资源的名称;当IRDE位于第三层目录时,Name表示代码页的编号。此外,还需要先判断Name的最高位是0还是1,如果是0则表示当做一个值来使用,如果是1,则表示低31位当做指针来使用;
  2. OffsetToData,指针;当最高位为1时,表示低位数据指向下一层目录;当最高位为0时,表示没有下一层目录,低位数据指向一个IMAGE_RESOURCE_DATA_ENTRY结构。
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {

    WORD    Length;

    WCHAR   NameString[ 1 ];

} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;

其中Length表示字符串的长度,NameString数组存储实际的Unicode字符。

IMAGE_RESOURCE_DATA_ENTRY结构体在WinNT.h头文件中的定义如下:

typedef struct _IMAGE_RESOURCE_DATA_ENTRY {

    DWORD   OffsetToData;

    DWORD   Size;

    DWORD   CodePage;

    DWORD   Reserved;

} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;      

IMAGE_RESOURCE_DATA_ENTRY结构体成员的介绍如下:

  1. OffsetToData,这是一个RVA,指向真正的资源数据;

  2. Size,表示资源的大小;

  3. CodePage,代码页,一般为0;

  4. Reserved,保留字段,暂时没有意义

2.9.重定位表解析

重定位操作由操作系统提供的装载器来完成,那么装载器是如何知道哪些数据需要进行重定位操作呢?这就涉及到我们即将介绍的重定位表了。

typedef struct _IMAGE_BASE_RELOCATION {

     DWORD   VirtualAddress;

     DWORD   SizeOfBlock;

     WORD    TypeOffset[1];

} IMAGE_BASE_RELOCATION;

该结构各个成员的介绍如下:

  1. VirtualAddress,RVA,指向当前这一组重定位数据开始的地址,各个重定项的值加上VirtualAddress计算出实际需要重定位操作的RVA值;
  2. SizeOfBlock,整个IMAGE_BASE_RELOCATION结构的大小,注意因为后面的TypeOffset数组的大小不固定,所以需要通过SizeOfBlock来指定整个结构的大小;
  3. TypeOffset,需要重定位的项,数组的项数可以通过(SizeOfBlock - 8)/2计算出来,数组每一项的大小占用2个字节,一共16位,其中高4位表示重定位的类型,低12位表示重定位的地址,低12位加上VirtualAddress得到实际上需要进行重定位操作的数据的RVA值;

常见的重定位类型有:

  1. IMAGE_REL_BASED_ABSOLUTE,值为0,没有具体意义,用于对齐使用;
  2. IMAGE_REL_BASED_HIGHLOW,值为3,表示指向的地址需要进行重定位修正;
  3. IMAGE_REL_BASED_DIR,值为10,出现在位的PE文件中,对指向的整个地址修正;

重定位表的结构如下图所示:

3.病毒分析

在线沙箱

网上有许多公开的在线沙箱,使用这些沙箱提供的服务,我们可以方便的观察一个程序的详细行为报告,进而判断一个程序大致的内部逻辑。

在线沙箱通常用于大致判定一个程序的行为是否安全,在逆向分析中,我们可以通过提交一个文件给沙箱程序来判断程序内部的大致逻辑,通过对沙箱报告的分析,有时候可以有效加快我们的逆向分析进程。

常见的在线沙箱包括但不限于:

VirusTotal:https://www.virustotal.com/gui/

VirSCAN:https://virscan.org/

微步云沙箱:https://s.threatbook.cn/

Joe Sandbox Cloud Basic:https://www.joesandbox.com/#windows

布谷鸟沙盒:https://sandbox.pikker.ee/

OPSWAT MetaDefender:https://metadefender.opswat.com/?lang=en

exe还可以用7z解压!

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务