标 题:santmat的reservesme-3 (10千字)
发信人:CoDe_inJect
时 间:2002-12-6 17:08:19
详细信息:

我们的目标是:没有驻牙!我晕。呵呵,这次我们的目标是santmat的reservesme-3
照例先看看说明
1. You must add a new section to the file by way of editing the PE header/Optional Header.
2. You must add the message box function to the file by adjusting the import table.
3. You must alter the entry point of the file to point to the message box code that is
within the new section.
4. After the execution of the message box, your code must jump back to the original
entry point of the file. - So the program can exit nicely using the already imported
ExitProcess ;)
5. IMPORTANT: You are only allowed to change the "PE Header/Optional Header" area of the
file and the area of the new section you add. You can't change any other sections.
Especially the import area.
6. FINALLY, You are only allowed to use hex/code editors(example: HIEW), you can use Wdasm or IDA, but I don't see what good they can do. You are not pe editors like procdump or the other numerous ones, or my IID King.
7. You must do it all by hand, that is what I am trying to get at here. You must do it
all manually. No help but your brain and an editor of some kind, for changing the
hex/code.
就是说必须手工构造一个section.在另加显示一个messagebox。当然少不了要手工在import table添加一个api
好正好复习一下pe heaher的知识。其实也是刚从看雪书里学的。^_^
先来看看有关知识:
section的结构
typedef struct _IMAGE_FILE_HEADER {
    USHORT  Machine;
    USHORT  NumberOfSections;
    ULONG  TimeDateStamp;
    ULONG  PointerToSymbolTable;
    ULONG  NumberOfSymbols;
    USHORT  SizeOfOptionalHeader;
    USHORT  Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
    一些 flags 的意思就是上边的USHORT  Characteristics
    0x00000020 contains code
    0x00000040 contains initialized data
    0x00000080 contains uninitialized data
    0x00000200 contains comments
    0x02000000 can be discarded
    0x10000000 This section is shareable.
    0x20000000 This section is executable.
    0x40000000 This section is readable.
    0x80000000 The section is writeable.
换成我要加的就是这样
section .inJect{
name='.inJect';//8 bytes
VirtualSize=100;//4 bytes
VirtualRVA=4000;//4 bytes
PhysicalSize=200;//4 bytes
PhysicalRVA=A00;//4 bytes
Unused=0;//12 bytes
Characteristics=E0000020;//4 bytes
}
pe header的结构
typedef struct _IMAGE_OPTIONAL_HEADER {
    //'pe'                4{the sigh of pe}
    // Standard fields.
    //dw number of section        8
    //
    USHORT  Magic;            26(always be 010bh)
    UCHAR  MajorLinkerVersion;        27    
    UCHAR  MinorLinkerVersion;
    ULONG  SizeOfCode;            32
    ULONG  SizeOfInitializedData;    36
    ULONG  SizeOfUninitializedData;
    ULONG  AddressOfEntryPoint;
    ULONG  BaseOfCode;
    ULONG  BaseOfData;
    //
    // NT additional fields.
    //
    ULONG  ImageBase;            56
    ULONG  SectionAlignment;
    ULONG  FileAlignment;
    USHORT  MajorOperatingSystemVersion;
    USHORT  MinorOperatingSystemVersion;
    USHORT  MajorImageVersion;
    USHORT  MinorImageVersion;
    USHORT  MajorSubsystemVersion;
    USHORT  MinorSubsystemVersion;
    ULONG  Reserved1;
    ULONG  SizeOfImage;        84
    ULONG  SizeOfHeaders;
    ULONG  CheckSum;
    USHORT  Subsystem;
    USHORT  DllCharacteristics;
    ULONG  SizeOfStackReserve;
    ULONG  SizeOfStackCommit;
    ULONG  SizeOfHeapReserve;
    ULONG  SizeOfHeapCommit;
    ULONG  LoaderFlags;
    ULONG  NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
import table结构,(import table通常都在某个section的开始)
typedef struct tagImportDirectory {
    DWORD    dwRVAFunctionNameList;
    DWORD    dwUseless1;
    DWORD    dwUseless2;
    DWORD    dwRVAModuleName;
    DWORD    dwRVAFunctionAddressList;
} IMAGE_IMPORT_MODULE_DIRECTORY, * PIMAGE_IMPORT_MODULE_DIRECTORY;
又来看看messageboxa的用法,其实上次已经贴了,这次是为自己作时方便
int MessageBox(
    HWND hWnd,    // handle of owner window
    LPCTSTR lpText,    // address of text in message box
    LPCTSTR lpCaption,    // address of title of message box 
    UINT uType     // s t y l e of message box
);
好要准备的知识已经全贴到这来了,再看看工具。
虽然sanmat说'You are only allowed to use hex/code editors',但他在美国(也不知道是不是美国佬),
再说也看不到,能用到的工具还是准备一下(偷偷用一下).
tools needs:
hex edit:ue
pe edit:pelord or other your favourite tools;(其实是作检查用的)
hiew:for modifying the exe's pcode;(我这里用了olly,改的方便。其实用hiewfu符合sanmat的要求。)
好,万事俱备,只欠pll621来改了,@_@.
First 我们来实现增加一个section
4小步
1) add the section.
2) Increase the number of sections
3) Increase Image Size
4) Add a new entry to the Section Table
用ue从0x410->600贴到exe尾部,为什么要贴这段,原因很简单,因为这段全0,第一步搞定.
用ue打开reme3.exe浏览一下pe head找pe标志,oh,find it at offset 0b0h
after 6 bytes at oxb6 you see the numbers of sections 0x03,so we just only
need change it to ox04,it's easy?(其实是想锻炼一下英语,大家不要骂,中国的crack应走向世界)第二步搞定

000000b0h: 50 45 00 00 4C 01 *03* 00 1A 9A DB 39 00 00 00 00 ; PE..L....氎9....
000000c0h: 00 00 00 00 E0 00 0F 01 0B 01 05 0C 00 02 00 00 ; ....?..........
to
000000b0h: 50 45 00 00 4C 01 @04@ 00 1A 9A DB 39 00 00 00 00 ; PE..L....氎9....
000000c0h: 00 00 00 00 E0 00 0F 01 0B 01 05 0C 00 02 00 00 ; ....?..........

Next we're going to increase the image size,其实在9x中没必要。但我用的2K.
size of image is located at offset 0x50 from the start of the PE sign so it is 0xb0+0x50=0x100
we see it's 0x4000 now,so we should chang it to 0x4000+0x1000=0x5000;
好到最后一步了。
加一个section head,前面已经把数据算好了,照着往上抄。这步完全手工,全靠pe知识。
Virtual Size 表示你的section实际用了多少空间,也就是不包括末尾的0。这里我用100。
Virtual RVA 表示你的section 从where load进内存,所以我们的就是前面的rva+1000.
Physical Size. 这个顾名思义,就是占空间大小。所以是我们section的长度,我贴的200,所以200 is 刚好
Physical RVA. 这个从字面意思也可理解,就是section开始物理地址,我们的从a00开始。
整理一下就是
+0 8byte name-only 8 so i use .inject
+8 dword virtual size -100
+C dword virtual address (an rva to where it should be mapped) ----->because .data was mapped to 0x3000 so ours to 0x4000
10 dword size of rawdata ----->just 0x200 here
14 dword pointerToRawData (file based offset) ----->我们的从0xa00开始
18 dword pointerToRelocations ----->没用 0x00000000
1C dword PointerToLinenumbers ----->没用 0x00000000
20 word NumberOfRelocations -----> the same
22 word NumberOfLineNumbers -----> the same
24 dword Characteristics -----> ours  is write read execute and code.so it's E0000020
00000220h: 2E 69 6E 6A 65 63 74 00 00 01 00 00 00 40 00 00 ; .inject......@..
00000230h: 00 02 00 00 00 0A 00 00 00 00 00 00 00 00 00 00 ; ................
00000240h: 00 00 00 00 20 00 00 E0 00 00 00 00 00 00 00 00 ; .... ..?.......
ok,the first step is done.
作完了这些,让我们偷偷用一下lord pe.看我们加的section对不对。一看发现一个问题inject的j显示的
太难看了,不过没关系。算了。
second: 添加一个api-messageboxa(user32.dll)
先大体说一下,pe文件先通过'pe'+80处标明一个输入表的地址,而输入表则以一个I_I_D数组开始,
每个被pe文件隐式连接进来的dll都有一个iid数组.接下来通常是一些由dll名和函数名组成的这个部分
排列没什么规律。
再来看看iid结构, 一个iid由0x20长度的数组组成。每8个字节为一组。
+0 DWORD OriginalFirstThunk;这个地方指明一个hint name array.通常跟firstthunk相同.这里只是备用.
4 DWORD TimeDateStamp;时间日期标志,可忽略.
8 DWORD ForwarderChain;向前连接索引
c DWORD Name;dll名称
10 DWORD FirstThunk;最有用的就是这个。指向一个array,这个array指明了调用的api名。一般jmp dword ptr [xxxxx]
都是通过这个翻译的。
先来定位一下import table的位置.at offset 0x80 from our PE sign is the a point to our import table
所以它的位置是0x80+0xb0=0x130
00000130h: 08 20 00 00 28 00 00 00 00 00 00 00 00 00 00 00 ; . ..(...........
根据前面的import table struct应得到iat start at 0x00002008 and size is 0x00000028
在这里需要强调的是2008 is va not rva so it should start at 608.(2000->600,so 2008->608).
let's take a look at 600
00000600h: 38 20 00 00 00 00 00 00 **30 20 00 00 00 00 00 00 ; 8 ......0 ......
00000610h: 00 00 00 00 46 20 00 00 00 20 00 00 00 00 00 00 ; ....F ... ......
00000620h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000630h: 38 20 00 00 00 00 00 00 75 00 45 78 69 74 50 72 ; 8 ......u.ExitPr
00000640h: 6F 63 65 73 73 00 4B 45 52 4E 45 4C 33 32 2E 64 ; ocess.KERNEL32.d
00000650h: 6C 6C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ll..............
00000660h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000670h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000680h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
I_I_D的结构
在这里先看看这个输入表 614指出了dll名2046(646)kernel32.dll,再看firstthunk部分2000(600)
内容(2038(638)这有几个dword(这几个dword就称为iat)就有几个函数输入)指向被调用函数看一下是exitprocess(前面有个dword)
整理一下
offset 00000A00        00002030------(2038)
offset 00000A04        00000000
offset 00000A08        00000000
offset 00000A0C        00002046
offset 00000A10        00002000------(2038)从这颗可看出or-thunk确实是firstthunk的备份
理解了它的,作自己的。
先说一下原理,先让import table 的指针指向我们新的iat,然后再我们新iat中调用原来的函数输入
20+我们的20+20个空格
增大原来的输入表长度先添个40,等会调整
00000130h: 08 20 00 00 28 00 00 00 00 00 00 00 00 00 00 00 ; . ..(...........
change to
00000130h: 08 40 00 00 40 00 00 00 00 00 00 00 00 00 00 00 ; .@..<...........
messageboxa的iid
offset 00000A14        00004044
offset 00000A18        00000000
offset 00000A1C        00000000
offset 00000A20        00004038
offset 00000A24        0000404c
按这个添加如图
00000a00h: 38 20 00 00 00 00 00 00 (1)30 20 00 00 00 00 00 00 ; 8 ......0 ......
00000a10h: 00 00 00 00 46 20 00 00 00 20 00 00 (2)44 40 00 00 ; ....F ... ..D@..
00000a20h: 00 00 00 00 00 00 00 00 54 40 00 00 4C 40 00 00 ; ........T@..L@..
The third:
显示一个messagebox,标题为。。,内容为。。。。这个在我的上一reverseme中一讲过。这里带过。
call messageboxa--->call 40404c
pusha
push 0 ;unused
push 0 ;unused
push 404090 ;caption
push 404070 ;text
push 0 ;unused
call d,[40404c] ;Call MessageBoxA
popa
push 0
jmp .401002 ;
总结一下,上一个reserseme是我对va,rva,offset,api,等概念有了了解.这个使我对pe的结构有了比较清晰的认识
特别是对输入表的认识.应该对以后脱壳有帮助吧.算法以后再练吧.总感觉越来越菜了.前辈们都不说话,使我们这些
小辈越来越菜了.

                                code_inject
                                2002.12.06

Copyright © 2000-2003 看雪学院(www.pediy.com) All Rights Reserved.