参考课件 chap06.pdf 中“通过修改PE装载DLL”一节的内容,以及课本第 5.5节的 内容,实现对notepad.exe(修復並下載Notepad.exe)的修改,使得修改后的 notepad.exe 在双击运行时,能够自动隐式装载 MyDll3.dll,并进而 将一个网页下载到本地index.html 文件。

本上机作业的目的是让大家深入理解 PE 文件中的导入表、导入地址表等关键结构及相关的功能。

  1. 本实验所使用的notepad.exe 是 Windows 7系统(最好32位版)中的可执行程序,MyDll3.dll 也仅保证在 Windows 7下能正常工作,因此,建议在 Windows 7环境(可预先安装虚拟机)下进行修改。请在虚拟机中禁用所有杀毒软件,确保修改过程不会受到杀毒软件的干扰。保证虚拟机能联网,以便DLL装载后的网页下载动作能正常完成。
  2. 下载notepad.exe可能与课本中所描述的notepad.exe版本不一致,应主要参考课件中的修改流程。
  3. 使用PEview分析PE文件,使用HxD编辑器修改PE文件。
  4. 直接使用本书所附代码编译生成 MyDll3.dll。

PE文件静态注入

这里因为notepad一直注入不成功,换了个win7版本也不行,好像是安全策略的原因,就只好找另外一个textview.exe进行注入

代码是李承远老师的逆向工程核心原理当中的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "stdio.h"
#include "windows.h"
#include "shlobj.h"
#include "Wininet.h"
#include "tchar.h"

#pragma comment(lib, "Wininet.lib")

#define DEF_BUF_SIZE (4096)
#define DEF_URL L"http://www.baidu.com/index.html"
#define DEF_INDEX_FILE L"index.html"
HWND g_hWnd = NULL;


#ifdef __cplusplus
extern "C" {
#endif
// 导出函数,但是没有任何功能,仅仅保持dll文件的形式上完整。
__declspec(dllexport) void dummy()
{
return;
}
#ifdef __cplusplus
}
#endif


//DownloadURL 下载 szURL 中指定网站的文件,并将其保存在 szFile 目录。
BOOL DownloadURL(LPCTSTR szURL, LPCTSTR szFile)
{
BOOL bRet = FALSE;
HINTERNET hInternet = NULL, hURL = NULL;
BYTE pBuf[DEF_BUF_SIZE] = { 0, };
DWORD dwBytesRead = 0;
FILE* pFile = NULL;
errno_t err = 0;

hInternet = InternetOpen(L"ReverseCore",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0);
if (NULL == hInternet)
{
OutputDebugString(L"InternetOpen() failed!");
return FALSE;
}

hURL = InternetOpenUrl(hInternet,
szURL,
NULL,
0,
INTERNET_FLAG_RELOAD,
0);
if (NULL == hURL)
{
OutputDebugString(L"InternetOpenUrl() failed!");
goto _DownloadURL_EXIT;
}

if (err = _tfopen_s(&pFile, szFile, L"wt"))
{
OutputDebugString(L"fopen() failed!");
goto _DownloadURL_EXIT;
}

while (InternetReadFile(hURL, pBuf, DEF_BUF_SIZE, &dwBytesRead))
{
if (!dwBytesRead)
break;

fwrite(pBuf, dwBytesRead, 1, pFile);
}

bRet = TRUE;

_DownloadURL_EXIT:
if (pFile)
fclose(pFile);

if (hURL)
InternetCloseHandle(hURL);

if (hInternet)
InternetCloseHandle(hInternet);

return bRet;
}


BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
DWORD dwPID = 0;

GetWindowThreadProcessId(hWnd, &dwPID);

if (dwPID == (DWORD)lParam)
{
g_hWnd = hWnd;
return FALSE;
}

return TRUE;
}

HWND GetWindowHandleFromPID(DWORD dwPID)
{
EnumWindows(EnumWindowsProc, dwPID);

return g_hWnd;
}


//DropFile 函数将下载的 index.html 文件 拖到 TextView_Path.exe进程并显示其内容。
BOOL DropFile(LPCTSTR wcsFile)
{
HWND hWnd = NULL;
DWORD dwBufSize = 0;
BYTE* pBuf = NULL;
DROPFILES* pDrop = NULL;
char szFile[MAX_PATH] = { 0, };
HANDLE hMem = 0;

WideCharToMultiByte(CP_ACP, 0, wcsFile, -1,
szFile, MAX_PATH, NULL, NULL);

dwBufSize = sizeof(DROPFILES) + strlen(szFile) + 1;

if (!(hMem = GlobalAlloc(GMEM_ZEROINIT, dwBufSize)))
{
OutputDebugString(L"GlobalAlloc() failed!!!");
return FALSE;
}

pBuf = (LPBYTE)GlobalLock(hMem);

pDrop = (DROPFILES*)pBuf;
pDrop->pFiles = sizeof(DROPFILES);
strcpy_s((char*)(pBuf + sizeof(DROPFILES)), strlen(szFile) + 1, szFile);

GlobalUnlock(hMem);

if (!(hWnd = GetWindowHandleFromPID(GetCurrentProcessId())))
{
OutputDebugString(L"GetWndHandleFromPID() failed!!!");
return FALSE;
}

PostMessage(hWnd, WM_DROPFILES, (WPARAM)pBuf, NULL);

return TRUE;
}


DWORD WINAPI ThreadProc(LPVOID lParam)
{
TCHAR szPath[MAX_PATH] = { 0, };
TCHAR* p = NULL;

OutputDebugString(L"ThreadProc() start...");

GetModuleFileName(NULL, szPath, sizeof(szPath));

if (p = _tcsrchr(szPath, L'\\'))
{
_tcscpy_s(p + 1, wcslen(DEF_INDEX_FILE) + 1, DEF_INDEX_FILE);

OutputDebugString(L"DownloadURL()");
if (DownloadURL(DEF_URL, szPath))
{
OutputDebugString(L"DropFlie()");
DropFile(szPath);
}
}

OutputDebugString(L"ThreadProc() end...");

return 0;
}




BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CloseHandle(CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL));
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

dummmy()函数实际是dll文件向外部提供服务的导出函数,但正如所见,它没有任何功能。既然如此,为何还要将其导出呢?这是为了保持形式上的完整性,mydll3.dll能够顺利添加到notepad_patch.exe文件的导入表。

生成的myhack3.dll

  1. 查看IDT是否有足够空间

我们从Image_Optional_Header的IMPORT Table得到结构体数组的RVA和Size

image-20221129084743308

通过查看image_section_header,发现RVA84CC处于rdata区域

image-20221129084920604

计算偏移

0x6000-0x5200 = 0xE00

文件偏移=即0x84CC -0xE00 = 0x76CC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct _IMAGE_IMPORT_DESCRIPTOR {

union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA 指向INT (PIMAGE_THUNK_DATA)
};

DWORD TimeDateStamp;

DWORD ForwarderChain; // -1 if no forwarders

DWORD Name; //dll 名称

DWORD FirstThunk; //指向引入函数真实地址单元处的RVA IAT

} IMAGE_IMPORT_DESCRIPTOR;

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

也可以将PEview调成文件偏移视图查看,可以看到文件偏移确实是0x76CC

image-20221129085530959

然后我们使用010 editor打开可以发现64Bytes的空间,有五个IDT结构体,最后一个为NULL,在我们的IDT之后紧贴着其它数据,我们没有足够的空间来添加一个0x14字节的结构体进去

image-20221129090351201

  1. 移动IDT

    从节区头信息可以得到,其内存virtual Size与文件的大小Size of Raw Data是不一样的

    image-20221129091817990

    .rdata 节区在磁盘文件中的大小为 2E00,而文件执行后被加载到内存时,程序实际使用的数据大小(映射大小)仅为 2C56 ,剩余未被使用的区域大小为 1AA (2E00 - 2C56)足够放下(0x14 * 6 = 0x78)字节的数据

    可以先从0x8C80开始存放我们的IDT(转化为文件偏移为0x7E80)(新IDT: 0x7E80到(0x7E80+0x78))

TextView.exe 文件中,导入表的 RVA 值为 84CC 。接下来,将导入表的 RVA 值更改为新 IDT 的 RVA 值 8C80,在 Size 原值64字节的基础上再加 14字节(IID 结构体的大小),修改为78字节

image-20221129092707789修改后导入表位于 RVA: 8C80(RAW : 7E80)地址处

先使用010 Editor完全复制原IDT(RAW:76CC~772F),然后覆盖到IDT的新位置(RAW:7E80)

image-20221129093114593image-20221129170652737

在7ED0处写入IID

image-20221129151000219

然后在新IDT尾部(RAW:7ED0)添加与mydll3对应的IID

image-20221129170916339

转到 7F00 地址处,输入相应值

image-20221129171549719

3.修改 IAT 节区的属性值

向原属性(ChAracteristics)40000040 添加 IMAGE_SCN_MEM_WRITE(80000000)属性值

也就是C0000040

image-20221129183917794

image-20221129184116973

使用 PEView 工具打开修改后的 TextView.exe 文件,查看其 IDT,发现已经装载上了myhack3.dll

image-20221129184229569 image-20221129184625924

点开,我们发现它成功下载了百度某个cdn下的index.html,并展示在文字框中

image-20221129184740738

参考文献

[[原创]通过修改PE加载DLL]https://bbs.pediy.com/thread-267045-1.htm

[通过修改PE文件的方式导入DLL]https://blog.csdn.net/fanxiaoyao1/article/details/125379489

李承远 逆向工程核心原理