加密壳实现

编译环境

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 }
LoadLibrary是加载一个dll到进程中,如果进程有这个dll,直接返回该dll的句柄;如果没有这个dll,就先把dll贴到进程空间,再返回该dll的句柄
参考:https://github.com/smallzhong/ycpack
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的影子

说明

这个壳子是滴水三期的一道课后项目作业

疑惑

在开发过程中,我发现壳子程序无法断点调试,因为壳子程序走到最后一节那块,必然要用指针指向一些内存,来拉伸最后一个节(源文件),而此时我们已经当做最后一个节已经加入了源文件,代码意图也很明显,但是事实是在编译过程中,我们还没有加壳过程。我们只是在编译自己的壳子,但是代码却是写给加壳后的。如果有师傅知道怎么调试,或者是我想法出了问题,请不吝赐教。

posted @ 2021-03-29 20:57  Punished  阅读(479)  评论(0编辑  收藏  举报