加密壳实现
编译环境
xp + vc6
加壳过程
把源文件(被保护的exe),加密后放入到壳子程序的最后一个节里
实现代码
宏
1 #define ENDPATH "C:\\LOADSHELL.exe" //加壳后文件存放的路径
壳子程序新增加节
参数说明:
path :要新增节文件的路径
n:要新增多少字节
LSADDRESS:得到新生成节的首地址
1 void addnewsec(IN LPSTR path,IN DWORD n,OUT LPVOID* LSADDRESS)
2 {
3 LPVOID FileBuffer = NULL;
4 LPVOID ImageBuffer = NULL;
5 LPVOID NewBuffer = NULL;
6 PIMAGE_DOS_HEADER pDosHeader = NULL;
7 PIMAGE_NT_HEADERS pNTHeader = NULL;
8 PIMAGE_FILE_HEADER pPEHeader = NULL;
9 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
10 PIMAGE_SECTION_HEADER pSectionHeader = NULL;
11 DWORD Size = 0;
12
13 FileToBigFileBuffer(path, n, &FileBuffer);
14
15 if (!FileBuffer)
16 {
17 printf("File->FileBuffer失败");
18 return;
19 }
20 FileBufferToBigImageBuffer(FileBuffer,n,&ImageBuffer);
21 if (!ImageBuffer)
22 {
23 printf("FileBUffer->ImageBuffer失败");
24 return;
25 }
26 pDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer;
27 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
28 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
29 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
30 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
31
32 PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader;
33 for (int i = 0; i < pPEHeader->NumberOfSections; i++, ptempSectionHeader++);
34
35 if ((pOptionHeader->SizeOfHeaders - ((DWORD)ptempSectionHeader - (DWORD)pDosHeader)) < 80)
36 {
37 MessageBox(0,"开辟新节表空间不够",0,0);
38 return;
39 }
40 memcpy(ptempSectionHeader, pSectionHeader,40);
41 pPEHeader->NumberOfSections = (WORD)pPEHeader->NumberOfSections + 1;
42 //printf("%x\n", pPEHeader->NumberOfSections);
43 pOptionHeader->SizeOfImage = (DWORD)pOptionHeader->SizeOfImage + n;
44 //printf("%x\n", pOptionHeader->SizeOfImage);
45 ptempSectionHeader->Misc.VirtualSize = n;
46 //printf("%x\n", ptempSectionHeader->Misc.VirtualSize);
47 PIMAGE_SECTION_HEADER ptempSectionHeader1 = ptempSectionHeader-1;
48 //判断内存大小和对齐后文件中大小,谁大加谁
49 if (ptempSectionHeader1->Misc.VirtualSize > ptempSectionHeader1->SizeOfRawData)
50 {
51 ptempSectionHeader->VirtualAddress = ptempSectionHeader1->VirtualAddress + ImageAlignment(ptempSectionHeader1->Misc.VirtualSize);
52 }
53 else
54 {
55 ptempSectionHeader->VirtualAddress = ptempSectionHeader1->VirtualAddress + ImageAlignment(ptempSectionHeader1->SizeOfRawData);
56 }
57 ptempSectionHeader->SizeOfRawData = FileAlignment(n);
58 ptempSectionHeader->PointerToRawData = ptempSectionHeader1->PointerToRawData + ptempSectionHeader1->SizeOfRawData;
59 ptempSectionHeader->Characteristics = pSectionHeader->Characteristics | ptempSectionHeader->Characteristics;
60 Size = ImageBufferToNewBuffer(ImageBuffer, &NewBuffer);
61 *LSADDRESS = (LPVOID)(ptempSectionHeader->VirtualAddress+(DWORD)ImageBuffer);
62 if (Size == 0 || !NewBuffer)
63 {
64 MessageBox(0,"ERROR(ImageBuffer->FileBuffer)",0,0);
65 free(FileBuffer);
66 free(ImageBuffer);
67 return;
68 }
69 BOOL isok = MemeryTOFile(NewBuffer, Size, ENDPATH);
70 if (isok == 0)
71 {
72 MessageBox(0,"存盘失败",0,0);
73 }
74 pshellImageBuffer = ImageBuffer;
75 free(NewBuffer);
76 free(FileBuffer);
77 return;
78 }
加密程序
1 DWORD encrypto(IN LPSTR path,OUT LPVOID* FileBuffer)
2 {
3 FILE* pFile;
4 pFile = fopen(path, "rb");
5 if (pFile == NULL)
6 {
7 fclose(pFile);//关闭文件
8 return 0;
9 }
10 else
11 {
12 fseek(pFile, 0, SEEK_END);
13 DWORD fileSize = ftell(pFile);
14 fseek(pFile, 0, SEEK_SET);
15 char* p = (char *)malloc(fileSize*sizeof(char)); //分配内存,读取文件
16 fread(p, sizeof(char), fileSize, pFile); //读取二进制到内存
17 for (DWORD i = 0; i < fileSize; i++)
18 {
19 p[i] = p[i] ^ 0xFF;
20 }
21 //写入二进制到文件
22 *FileBuffer = p;
23 fclose(pFile);//关闭文件
24 return fileSize;
25 }
26 }
这里的加密算法可以更复杂,我只是简单的进行异或
真正将源文件加载到壳子中
1 DWORD addshellcodeTolastSection(LPSTR srcpath,LPSTR despath)
2 {
3 LPVOID NewBuffer = NULL;
4 LPVOID pFileBuffer = NULL;
5 LPVOID LSADDRESS = NULL;
6 int FileSize = encrypto(srcpath,&pFileBuffer);
7 addnewsec(despath,FileSize,&LSADDRESS); //增加节的新文件已经存在ENDPATH中
8 memcpy(LSADDRESS,pFileBuffer,FileSize);
9 DWORD Size = ImageBufferToNewBuffer(pshellImageBuffer, &NewBuffer);
10
11 BOOL isok = MemeryTOFile(NewBuffer, Size, ENDPATH);
12 if (isok == 0)
13 {
14 MessageBox(0,"存盘失败",0,0);
15 }
16 free(pshellImageBuffer);
17 free(pFileBuffer);
18 free(NewBuffer);
19 return 1;
20 }
用到的一些映像操作函数
1 DWORD ImageBufferToNewBuffer(IN LPVOID pImageBuffer, OUT LPVOID* pNewBuffer)
2 {
3 if (!pImageBuffer)
4 {
5 printf("PE文件读取失败");
6 return 0;
7 }
8 if (*(PWORD)pImageBuffer != IMAGE_DOS_SIGNATURE)
9 {
10 printf("不是有效的MZ头");
11 free(pImageBuffer);
12 return 0;
13 }
14 DWORD FileSize = 0;
15 LPVOID ptempNewBuffer = NULL;
16 PIMAGE_DOS_HEADER pDosHeader = NULL;
17 PIMAGE_NT_HEADERS pNTHeader = NULL;
18 PIMAGE_FILE_HEADER pPEHeader = NULL;
19 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
20 PIMAGE_SECTION_HEADER pSectionHeader = NULL;
21
22 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
23 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
24 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
25 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
26 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
27 PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader;
28
29 if (*(PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE)
30 {
31 printf("不是有效的PE签名");
32 free(pImageBuffer);
33 return 0;
34 }
35
36 for (int i = 0; i < pPEHeader->NumberOfSections; i++, ptempSectionHeader++);
37
38 ptempSectionHeader--;
39 FileSize = ptempSectionHeader->PointerToRawData + ptempSectionHeader->SizeOfRawData;
40
41 ptempNewBuffer = malloc(FileSize);
42 if (!ptempNewBuffer)
43 {
44 printf("申请pNewBuffer堆空间失败");
45 return 0;
46 }
47 memset(ptempNewBuffer, 0, FileSize);
48 memcpy(ptempNewBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);
49
50 PIMAGE_SECTION_HEADER ptemp1SectionHeader = pSectionHeader;
51
52 for (DWORD n = 0; n < pPEHeader->NumberOfSections; n++)
53 {
54 memcpy((void*)((DWORD)ptempNewBuffer+ptemp1SectionHeader->PointerToRawData), (void*)((DWORD)pImageBuffer + ptemp1SectionHeader->VirtualAddress), ptemp1SectionHeader->SizeOfRawData);
55 //printf("%x\n", ptemp1SectionHeader->SizeOfRawData);
56 ptemp1SectionHeader++;
57 }
58
59 *pNewBuffer = ptempNewBuffer;
60 ptemp1SectionHeader = NULL;
61 return FileSize;
62 }
1 DWORD MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile)
2 {
3 FILE* pFile = NULL;
4 if (!pMemBuffer)
5 {
6 printf("读取内存失败");
7 return 0;
8 }
9 pFile = fopen(lpszFile, "wb");
10 if (!pFile)
11 {
12 printf("创建exe失败");
13 return 0;
14 }
15 size_t n = fwrite(pMemBuffer, size, 1, pFile);
16 if (!n)
17 {
18 printf("存盘失败");
19 free(pMemBuffer);
20 fclose(pFile);
21 pFile = NULL;
22 return 0;
23 }
24 fclose(pFile);
25 pFile = NULL;
26 return 1;
27 }
解壳过程
解壳过程就是编写壳子的过程,因为解壳程序都在壳子程序中,也是最关键的一环
实现代码
一些要用到的函数
1 DWORD FileAlignment(int n)
2 {
3 DWORD i;
4 if (n % 0x200 != 0)
5 {
6 i = n / 0x200 + 1;
7 i = i * 0x200;
8 return i;
9 }
10 else
11 {
12 i = n / 0x200;
13 i = i * 0x200;
14 return i;
15 }
16 }
17 DWORD ImageAlignment(int n)
18 {
19 DWORD i;
20 if (n % 0x1000 != 0)
21 {
22 i = n / 0x1000 + 1;
23 i = i * 0x1000;
24 return i;
25 }
26 else
27 {
28 i = n / 0x1000;
29 i = i * 0x1000;
30 return i;
31 }
32 }
33 DWORD RvaToFoa(IN LPSTR PATH,IN DWORD rva)
34 //参数为内存偏移,返回文件偏移
35 {
36 LPVOID FileBuffer = NULL;
37 LPVOID ImageBuffer = NULL;
38 DWORD Foa = 0;
39 PIMAGE_DOS_HEADER pDosHeader = NULL;
40 PIMAGE_NT_HEADERS pNTHeader = NULL;
41 PIMAGE_FILE_HEADER pPEHeader = NULL;
42 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
43 PIMAGE_SECTION_HEADER pSectionHeader = NULL;
44
45 FileToFileBuffer(PATH, &FileBuffer);
46
47 if (!FileBuffer)
48 {
49 printf("File->FileBuffer失败");
50 return 0;
51 }
52 FileBufferToImageBuffer(FileBuffer, &ImageBuffer);
53 if (!ImageBuffer)
54 {
55 printf("FileBUffer->ImageBuffer失败");
56 return 0;
57 }
58 pDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer;
59 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
60 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
61 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
62 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
63
64 PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader;
65 PIMAGE_SECTION_HEADER ptempSectionHeader1 = pSectionHeader;
66 for (int i = 0; i < pPEHeader->NumberOfSections; i++, ptempSectionHeader++);
67 //printf("%x\n", FileAlignment(((DWORD)ptempSectionHeader - (DWORD)ImageBuffer)));
68 if (rva <= FileAlignment(((DWORD)ptempSectionHeader - (DWORD)ImageBuffer)))
69 {
70 Foa = rva;
71 free(FileBuffer);
72 free(ImageBuffer);
73 return Foa;
74 }
75 for (int k = 0; k < pPEHeader->NumberOfSections-1; k++)
76 {
77 if (ptempSectionHeader1->VirtualAddress < rva && rva < (ptempSectionHeader1 + 1)->VirtualAddress)
78 {
79 Foa = ptempSectionHeader1->PointerToRawData + (rva - ptempSectionHeader1->VirtualAddress);
80 free(FileBuffer);
81 free(ImageBuffer);
82 return Foa;
83 }
84 if (ptempSectionHeader1->VirtualAddress == rva)
85 {
86 Foa = ptempSectionHeader1->PointerToRawData;
87 free(FileBuffer);
88 free(ImageBuffer);
89 return Foa;
90 }
91 ptempSectionHeader1++;
92 }
93 if (ptempSectionHeader1->VirtualAddress <= rva)
94 {
95 Foa = ptempSectionHeader1->PointerToRawData + (rva - ptempSectionHeader1->VirtualAddress);
96 free(FileBuffer);
97 free(ImageBuffer);
98 return Foa;
99 }
100 free(FileBuffer);
101 free(ImageBuffer);
102 return 0;
103 }
104
105
106 DWORD FileToFileBuffer(IN LPSTR lpszFile, OUT LPVOID* FileBuffer)
107 {
108 FILE* pFile = NULL;
109 LPVOID ptempFileBuffer = NULL;
110 DWORD fileSize = 0;
111 //打开文件
112 pFile = fopen(lpszFile, "rb");
113 //判断文件是否打开
114 if (!pFile)
115 {
116 printf("无法打开文件");
117 return 0;
118 }
119 //malloc文件大小
120 fseek(pFile, 0, SEEK_END);
121 fileSize = ftell(pFile);
122 fseek(pFile, 0, SEEK_SET);
123 ptempFileBuffer = malloc(fileSize);
124 memset(ptempFileBuffer,0,fileSize);
125 //判断是否申请空间成功
126 if (!ptempFileBuffer)
127 {
128 printf("分配空间失败");
129 fclose(pFile);
130 return 0;
131 }
132 size_t n = fread(ptempFileBuffer, fileSize, 1, pFile);
133 //判断是否拷贝成功
134 if (!n)
135 {
136 printf("拷贝数据失败");
137 free(ptempFileBuffer);
138 fclose(pFile);
139 return 0;
140 }
141 *FileBuffer = ptempFileBuffer;
142 ptempFileBuffer = NULL;
143 fclose(pFile);
144 return fileSize;
145 }
146 DWORD FileBufferToImageBuffer(IN LPVOID pFileBuffer, OUT LPVOID* pImageBuffer)
147 {
148
149 LPVOID p1ImageBuffer = NULL;
150 PIMAGE_DOS_HEADER pDosHeader = NULL;
151 PIMAGE_NT_HEADERS pNTHeader = NULL;
152 PIMAGE_FILE_HEADER pPEHeader = NULL;
153 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
154 PIMAGE_SECTION_HEADER pSectionHeader = NULL;
155 pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
156
157 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
158
159 pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
160
161 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
162
163 pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
164 p1ImageBuffer = malloc(pOptionHeader->SizeOfImage);
165 if (!p1ImageBuffer)
166 {
167 printf("申请ImageBuffer堆空间失败");
168 return 0;
169 }
170 memset(p1ImageBuffer , 0 , pOptionHeader->SizeOfImage);
171 memcpy(p1ImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);
172 PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader;
173
174 for (int k = 0; k < pPEHeader->NumberOfSections; k++)
175 {
176 memcpy((void*)((DWORD)p1ImageBuffer+ ptempSectionHeader->VirtualAddress), (void*)((DWORD)pFileBuffer + ptempSectionHeader->PointerToRawData), ptempSectionHeader->SizeOfRawData);
177 //printf("%x\n", ptempSectionHeader->SizeOfRawData);
178 ptempSectionHeader++;
179 }
180
181 *pImageBuffer = p1ImageBuffer;
182 ptempSectionHeader = NULL;
183 return pOptionHeader->SizeOfImage;
184 }
关键代码,思路最重要
一:获取自身文件的路径:因为我们需要将自身文件展开到内存来进行操作.
1 CHAR path[MAX_PATH];
2 DWORD dwTempImageBaseSrc = NULL;
3 HMODULE hm=GetModuleHandle(NULL);
4 GetModuleFileName(hm,path,sizeof(path));
5 FileToFileBuffer(path, &pzzFileBuffer);
用到的API: GetModuleHandle GetModuleFileName
二:解密.
for (DWORD i = 1; i < pPEHeader->NumberOfSections; i++, pSectionHeader++); //定位到最后一个节 源文件在这里
CHAR* SrcMoule = (CHAR*)((DWORD)pzzFileBuffer + pSectionHeader->PointerToRawData);
//解密
for(k = 0;k<pSectionHeader->SizeOfRawData;k++)
{
SrcMoule[k] = SrcMoule[k] ^ 0xFF;
}
三:将解密后的源文件,在内存中拉伸
FileBufferToImageBuffer(SrcMoule,&pImageBuffer);
四:以挂起方式创建一个进程
1 STARTUPINFO ie_si = {0};
2 PROCESS_INFORMATION ie_pi;
3 TCHAR SrcBuffer[256] = {0};
4 sprintf(SrcBuffer,"%s",path);
5 ie_si.cb = sizeof(ie_si);
6 CreateProcess( //以挂起的方式创建进程
7 NULL,
8 SrcBuffer,
9 NULL,
10 NULL,
11 FALSE,
12 CREATE_SUSPENDED,
13 NULL,
14 NULL,
15 &ie_si,
16 &ie_pi
17 );
主要目的是为了起后面的源文件,创建进程的路径就写自己本身
关键参数:CREATE_SUSPENDED (以挂起方式创建)
用到的API:CreateProcess
五:卸载外壳程序
API:ZwUnmapViewOfSection
1 NTSTATUS ZwUnmapViewOfSection(
2 IN HANDLE ProcessHandle,
3 IN PVOID BaseAddress );
这个函数在 wdm.h 里声明,它的功能是卸载进程的内存镜像(Image Buffer),内存镜像是指进程4GB虚拟地址空间中从 ImageBase 开始,长度为 SizeOfImage 的内存。
wdm.h 这个头文件需要安装wdk 微软链接 https://docs.microsoft.com/zh-cn/windows-hardware/drivers/download-the-wdk
也可以通过ntdll这个dll,将ZwUnmapViewOfSection函数通过GetProcAddress找到函数地址,再把函数地址赋给函数名,并不直接调用
1 pfnZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
2 HMODULE hModule = LoadLibrary("ntdll.dll");
3 if (hModule)
4 {
5 ZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)GetProcAddress(hModule, "ZwUnmapViewOfSection");
6 if (ZwUnmapViewOfSection)
7 {
8 if (ZwUnmapViewOfSection((unsigned long)ie_pi.hProcess, dwImageBaseShell))
9 { // 卸载掉 壳子程序自身的ImageBase 地址
10 printf("ZwUnmapViewOfSection success\n");
11 }
12 }
13 FreeLibrary(hModule);
14 }
1 FARPROC GetProcAddress(
2 HMODULE hModule, // DLL模块句柄
3 LPCSTR lpProcName // 函数名
4 );
六:分配空间
1 FirstAD = VirtualAllocEx(ie_pi.hProcess,(LPVOID)pSrcOptionHeader->ImageBase,pSrcOptionHeader->SizeOfImage,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
2 if(FirstAD == NULL)
3 {
4 if(pSrcOptionHeader->DataDirectory[5].VirtualAddress == 0 || pSrcOptionHeader->DataDirectory[5].Size ==0)
5 {
6 MessageBox(0,"shibai",0,0);
7 return;
8 }
9 else
10 {
11 DWORD RVA_Data;
12 WORD reloData;
13 PWORD Location = NULL;
14 DWORD NumberOfRelocation = 0;
15 dwTempImageBaseSrc = pSrcOptionHeader->ImageBase + 0x50000;
16 DWORD fOA = RvaToFoa(path,pSrcOptionHeader->DataDirectory[5].VirtualAddress);
17 PIMAGE_BASE_RELOCATION pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)SrcMoule + fOA);
18 //申请空间
19 VirtualAllocEx(ie_pi.hProcess, (LPVOID)dwTempImageBaseSrc,pSrcOptionHeader->SizeOfImage,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
20 pSrcOptionHeader->ImageBase = (DWORD)dwTempImageBaseSrc;
21 WriteProcessMemory(ie_pi.hProcess, (LPVOID)dwTempImageBaseSrc, pImageBuffer, pSrcOptionHeader->SizeOfImage, NULL);
22 while(pRelocationDirectory->SizeOfBlock && pRelocationDirectory->VirtualAddress){
23 NumberOfRelocation = (pRelocationDirectory->SizeOfBlock - 8)/2;// 每个重定位块中的数据项的数量
24 Location = (PWORD)((DWORD)pRelocationDirectory + 8); // 加上8个字节
25 for(DWORD i=0;i<NumberOfRelocation;i++){
26 if(Location[i] >> 12 != 0){ //判断是否是垃圾数据
27 // WORD类型的变量进行接收
28 reloData = (Location[i] & 0xFFF); //这里进行与操作 只取4字节 二进制的后12位
29 RVA_Data = pRelocationDirectory->VirtualAddress + reloData; //这个是RVA的地址
30 fOA = RvaToFoa(SrcMoule,RVA_Data);
31 *(PDWORD)((DWORD)SrcMoule+(DWORD)fOA) = *(PDWORD)((DWORD)SrcMoule+(DWORD)fOA) + dwTempImageBaseSrc - pSrcOptionHeader->ImageBase; // 任意位置 - Origin ImageBase
32 }
33 }
34 pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationDirectory + (DWORD)pRelocationDirectory->SizeOfBlock); //上面的for循环完成之后,跳转到下个重定位块 继续如上的操作
35 }
36 }
37 }
38 else
39 {
40 WriteProcessMemory(ie_pi.hProcess, (LPVOID)pSrcOptionHeader->ImageBase, pImageBuffer,pSrcOptionHeader->SizeOfImage,NULL);
41 }
这里有一个判断,就是如果我们按照他本身的ImageBase来分配空间的话,有可能分配失败,可能这个位置已经被占用,这时如果源文件还有重定位表,就可以分配另一块内存并修复重定位表,如果没有重定位表则直接返回失败.
一点重定位表的理解:人人都想抢0x400000 这个位置,但总有人抢不到,抢不到的人,比如某一个dll,就以模块对齐的方式贴在了这个位置的后面,而有一些地址随着ImageBase的偏移而偏移,模块提供了这张表,记录了哪些地址是跟ImageBase息息相关的,当我们移动了ImageBase后,修复这张表,地址依旧准确
重定位表的定位与结构:
七:修改外壳程序的上下文
1 //修改外壳程序的Context
2 CONTEXT context;
3 context.ContextFlags = CONTEXT_FULL;
4 BOOL ok = ::GetThreadContext(ie_pi.hThread,&context);
5 CHAR* baseAddress = (CHAR*)context.Ebx+8;
6 DWORD dwEntryPoint = pSrcOptionHeader->AddressOfEntryPoint;
7 context.Eax = dwEntryPoint+(DWORD)dwBufferImageBaseSrc;
8
9 DWORD theOep = context.Ebx + 8;
10 DWORD dwBytes=0;
11 WriteProcessMemory(ie_pi.hProcess, &theOep, &dwBufferImageBaseSrc,4, &dwBytes);
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesWritten
);
八:记得恢复进程
1 //恢复执行
2 SetThreadContext(ie_pi.hThread, &context);
3 //记得恢复线程
4 ResumeThread(ie_pi.hThread);
5 ExitProcess(0);
6 return;
查看效果
选取的是一个cmd作为源文件
用LoadPE进行比较
程序入口和镜像大小都完全改变,已经在壳子中看不到任何cmd的影子
说明
这个壳子是滴水三期的一道课后项目作业
疑惑
在开发过程中,我发现壳子程序无法断点调试,因为壳子程序走到最后一节那块,必然要用指针指向一些内存,来拉伸最后一个节(源文件),而此时我们已经当做最后一个节已经加入了源文件,代码意图也很明显,但是事实是在编译过程中,我们还没有加壳过程。我们只是在编译自己的壳子,但是代码却是写给加壳后的。如果有师傅知道怎么调试,或者是我想法出了问题,请不吝赐教。