-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3d583e6
commit 3e078a2
Showing
33 changed files
with
1,233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Prerequisites | ||
*.d | ||
|
||
# Compiled Object files | ||
*.slo | ||
*.lo | ||
*.o | ||
*.obj | ||
|
||
# Precompiled Headers | ||
*.gch | ||
*.pch | ||
|
||
# Compiled Dynamic libraries | ||
*.so | ||
*.dylib | ||
*.dll | ||
|
||
# Fortran module files | ||
*.mod | ||
*.smod | ||
|
||
# Compiled Static libraries | ||
*.lai | ||
*.la | ||
*.a | ||
*.lib | ||
|
||
# Executables | ||
*.exe | ||
*.out | ||
*.app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,61 @@ | ||
# ycpack | ||
傀儡进程加密壳 滴水三期课后作业 | ||
|
||
## 项目说明 | ||
|
||
+ 本项目是[滴水三期视频](https://www.bilibili.com/video/BV1yt41127Cd)的一个课后作业,是使用 **傀儡进程** 方法写的一个 **玩具** 壳 | ||
|
||
+ 壳主体的工作步骤如下 | ||
|
||
1. 读取主模块的数据 | ||
2. 解密:得到原来的PE文件 | ||
3. 以挂起的形式创建进程: `CreateProcess` ,要创建的进程,就是壳子本身 | ||
4. 获取外壳程序的Context,后面要用. | ||
5. 卸载外壳程序. | ||
6. 在指定的位置分配空间:位置就是src的ImageBase 大小就是Src的SizeOfImage | ||
7. 如果成功,将Src的PE文件拉伸 复制到该空间中 | ||
8. 如果申请空间失败,但有重定位表:在任意位置申请空间,然后将PE文件拉伸、复制、修复重定位表。 | ||
9. 如果第6步申请空间失败,并且还没有重定位表,直接返回:失败。 | ||
10. 修改外壳程序的Context: | ||
|
||
+ 将Context的ImageBase 改成 Src的ImageBase | ||
+ 将Context的OEP 改成 Src的OEP | ||
11. 设置Context 并恢复主线程 | ||
12. 终止外壳程序,解壳过程结束. | ||
|
||
+ 加壳机的工作步骤如下 | ||
|
||
1. 获取Shell程序的路径 | ||
2. 获取src程序的路径 | ||
3. 将src程序读取到内存中,加密 | ||
4. 在Shell程序中新增一个节,并将加密后的src程序追加到Shell程序的新增节中 | ||
5. 加壳过程完毕 | ||
|
||
## 编译环境 | ||
|
||
XP系统 + VC6 | ||
|
||
> 注意:不能用Visual Studio来编译。在VS中有些函数的参数会从 `LPSTR` 变为宽字符的 `LPWSTR` ,而且在VS中 `TCHAR` 是 `WCHAR` 而在VC6中 `TCHAR` 是 `CHAR` 。所以在VS中一定编译不过。 | ||
## 使用方法 | ||
|
||
**注:只支持给32位程序加壳,不能给64位程序加壳!** | ||
|
||
+ 将加壳机和壳本体编译出来(或者在 **release** 中下载已经编译好的EXE),双击加壳机输入壳本体和需要加壳的源程序的位置,并输入需要保存的位置即可生成加壳后的程序。 | ||
|
||
![image-20200818202707995](https://raw.githubusercontent.com/smallzhong/picgo-pic-bed/master/image-20200818202707995.png) | ||
|
||
+ 加壳后可正常运行。 | ||
|
||
![image-20200818202908354](https://raw.githubusercontent.com/smallzhong/picgo-pic-bed/master/image-20200818202908354.png) | ||
|
||
|
||
|
||
## 待完成功能 | ||
|
||
- [ ] 在加壳的时候通过加密算法(如异或)给源程序加密 | ||
- [ ] 当 `VirtualAllocEx` 分配空间失败时判断是否有重定位表并重新申请空间 | ||
|
||
## 鸣谢 | ||
|
||
+ 本项目中使用了部分[@adezz](https://github.com/adezz)用户的[Shell-Of-Water](https://github.com/adezz/Shell-Of-Water)项目中的代码 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
#include "StdAfx.h" | ||
#include "head.h" | ||
|
||
int main() | ||
{ | ||
LPVOID pFileBuffer = NULL; | ||
PIMAGE_DOS_HEADER pDosHeader = NULL; | ||
PIMAGE_NT_HEADERS32 pNTHeader = NULL; | ||
PIMAGE_SECTION_HEADER pSectionHeader = NULL; | ||
|
||
LPVOID pFileBuffer_src = NULL; | ||
PIMAGE_DOS_HEADER pDosHeader_src = NULL; | ||
PIMAGE_NT_HEADERS32 pNTHeader_src = NULL; | ||
PIMAGE_SECTION_HEADER pSectionHeader_src = NULL; | ||
|
||
char file_path_shell[256]; | ||
char file_path_src[256]; | ||
memset(file_path_shell, 0, 256); | ||
memset(file_path_src, 0, 256); | ||
|
||
printf("请输入壳程序的位置:"); | ||
scanf("%s", file_path_shell); | ||
printf("请输入源程序的位置:"); | ||
scanf("%s", file_path_src); | ||
|
||
DWORD file_size = ReadPEFile(file_path_shell, pFileBuffer, pDosHeader, | ||
pNTHeader, pSectionHeader); | ||
|
||
// 读取源文件 | ||
DWORD file_size_src = ReadPEFile(file_path_src, pFileBuffer_src, pDosHeader_src, | ||
pNTHeader_src, pSectionHeader_src); | ||
|
||
// 新增节 | ||
LPVOID pNewFileBuffer = NULL; | ||
AddNewSec(&pNewFileBuffer, pFileBuffer, pDosHeader, pNTHeader, pSectionHeader, file_size, file_size_src); | ||
file_size += file_size_src; // 更新文件大小 | ||
pFileBuffer = pNewFileBuffer; | ||
// 复制到后面 | ||
memcpy( | ||
(LPVOID)((PBYTE)pFileBuffer + file_size - file_size_src), | ||
pFileBuffer_src, | ||
file_size_src | ||
); | ||
|
||
char file_path_out[256]; | ||
memset(file_path_out, 0, 256); | ||
printf("加壳已完成,请输入要保存的位置:"); | ||
scanf("%s", file_path_out); | ||
FILE* fp_out; | ||
fp_out = fopen(file_path_out, "wb"); | ||
MY_ASSERT(fp_out); | ||
fwrite(pFileBuffer, file_size, 1, fp_out); | ||
fclose(fp_out); | ||
} | ||
|
||
void AddNewSec(OUT LPVOID* pNewFileBuffer, IN LPVOID pFileBuffer, PIMAGE_DOS_HEADER pDosHeader, | ||
PIMAGE_NT_HEADERS32 pNTHeader, | ||
PIMAGE_SECTION_HEADER pSectionHeader, DWORD file_size, DWORD dwAddSize) | ||
{ | ||
PIMAGE_FILE_HEADER pImageFileHeader = | ||
(PIMAGE_FILE_HEADER)((PBYTE)pDosHeader + pDosHeader->e_lfanew + 4); | ||
|
||
PIMAGE_OPTIONAL_HEADER32 pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)( | ||
(PBYTE)pImageFileHeader + sizeof(IMAGE_FILE_HEADER)); | ||
|
||
if (((PBYTE)pImageOptionalHeader->SizeOfHeaders - | ||
((PBYTE)pDosHeader->e_lfanew + IMAGE_SIZEOF_FILE_HEADER + | ||
pImageFileHeader->SizeOfOptionalHeader + | ||
40 * pImageFileHeader->NumberOfSections)) < 80) | ||
EXIT_ERROR("空间不足,新增节表失败!"); | ||
|
||
DWORD numOfSec = pImageFileHeader->NumberOfSections; | ||
// 1) 添加一个新的节表(可以copy一份) | ||
memcpy( | ||
(LPVOID)(pSectionHeader + numOfSec), // 需要新增的位置 | ||
(LPVOID)(pSectionHeader), // 第一个节 | ||
sizeof(IMAGE_SECTION_HEADER) | ||
); // 将第一个节(代码节)拷贝 | ||
|
||
// 2) 在新增节后面 填充一个节大小的000 | ||
memset((LPVOID)(pSectionHeader + numOfSec + 1), 0, sizeof(IMAGE_SECTION_HEADER)); | ||
|
||
|
||
// 3) 修改PE头中节的数量 | ||
pImageFileHeader->NumberOfSections += 1; | ||
|
||
// 4) 修改sizeOfImage的大小 | ||
pImageOptionalHeader->SizeOfImage += 0x1000; | ||
|
||
// 5)修正新增节表的属性 | ||
// 修改该节表的名字 | ||
memcpy((LPVOID)(pSectionHeader + numOfSec), g_NameOfNewSectionHeader, sizeof(g_NameOfNewSectionHeader)); | ||
// 修改该节表中其他必要属性 | ||
(pSectionHeader + numOfSec)->Misc.VirtualSize = 0x1000; // 对齐前的大小,设为1000即可 | ||
// 根据前一个节表的属性修改virtualAddress | ||
DWORD t_Add = 0; // (pSectionHeader + numOfSec - 1)->VirtualAddress 加上 t_Add 为VirtualAddress | ||
|
||
if ((pSectionHeader + numOfSec - 1)->Misc.VirtualSize < (pSectionHeader + numOfSec - 1)->SizeOfRawData) | ||
{ // 如果VirtualSize小于SizeOfRawData | ||
t_Add = (pSectionHeader + numOfSec - 1)->SizeOfRawData; | ||
} | ||
else | ||
{ | ||
if (((pSectionHeader + numOfSec - 1)->Misc.VirtualSize % 0x1000) == 0) // 如果其能被0x1000整除 | ||
t_Add = (pSectionHeader + numOfSec - 1)->Misc.VirtualSize; | ||
else | ||
t_Add = ((((pSectionHeader + numOfSec - 1)->Misc.VirtualSize / 0x1000) + 1)) * 0x1000; | ||
} | ||
MY_ASSERT(t_Add); | ||
(pSectionHeader + numOfSec)->VirtualAddress = (pSectionHeader + numOfSec - 1)->VirtualAddress | ||
+ t_Add; | ||
// 修改sizeofRawData | ||
(pSectionHeader + numOfSec)->SizeOfRawData = 0x1000; | ||
// 更新PointerToRawData | ||
(pSectionHeader + numOfSec)->PointerToRawData = (pSectionHeader + numOfSec - 1)->PointerToRawData + | ||
(pSectionHeader + numOfSec - 1)->SizeOfRawData; | ||
// (pSectionHeader + numOfSec)->Characteristics = (pSectionHeader->Characteristics | (pSectionHeader + numOfSec - 1)->Characteristics); | ||
|
||
// 6) 在原有数据的最后,新增一个节的数据(内存对齐的整数倍) (复制到新的LPVOID中去) | ||
*pNewFileBuffer = malloc(file_size + dwAddSize); | ||
memcpy(*pNewFileBuffer, pFileBuffer, file_size); | ||
} | ||
|
||
DWORD ReadPEFile(IN LPSTR file_in, OUT LPVOID& pFileBuffer, | ||
PIMAGE_DOS_HEADER& pDosHeader, PIMAGE_NT_HEADERS32& pNTHeader, | ||
PIMAGE_SECTION_HEADER& pSectionHeader) | ||
{ | ||
FILE* fp; | ||
fp = fopen(file_in, "rb"); | ||
if (!fp) | ||
EXIT_ERROR("fp == NULL!"); | ||
DWORD file_size = 0; | ||
fseek(fp, 0, SEEK_END); | ||
file_size = ftell(fp); | ||
fseek(fp, 0, SEEK_SET); | ||
|
||
LPVOID t = malloc(file_size); | ||
if ((fread(t, file_size, 1, fp) != 1) || t == NULL) | ||
EXIT_ERROR("fread error or malloc error!"); | ||
|
||
pFileBuffer = t; | ||
MY_ASSERT(pFileBuffer); | ||
|
||
pDosHeader = (PIMAGE_DOS_HEADER)(pFileBuffer); | ||
MY_ASSERT(pDosHeader); | ||
MY_ASSERT((pDosHeader->e_magic == IMAGE_DOS_SIGNATURE)); | ||
|
||
pNTHeader = | ||
(PIMAGE_NT_HEADERS32)((PBYTE)pFileBuffer + pDosHeader->e_lfanew); | ||
if (pNTHeader->FileHeader.SizeOfOptionalHeader != 0xe0) | ||
EXIT_ERROR("this is not a 32-bit executable file."); | ||
|
||
pSectionHeader = (PIMAGE_SECTION_HEADER)( | ||
(PBYTE)pNTHeader + sizeof(IMAGE_NT_SIGNATURE) + | ||
sizeof(IMAGE_FILE_HEADER) + pNTHeader->FileHeader.SizeOfOptionalHeader); | ||
fclose(fp); | ||
return file_size; | ||
} | ||
|
||
DWORD RVA_TO_FOA(LPVOID pFileBuffer, PIMAGE_DOS_HEADER pDosHeader, | ||
PIMAGE_NT_HEADERS32 pNTHeader, | ||
PIMAGE_SECTION_HEADER pSectionHeader, IN DWORD RVA) | ||
{ | ||
if (RVA < pNTHeader->OptionalHeader.SizeOfHeaders) | ||
return RVA; | ||
|
||
for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++) | ||
{ | ||
if (RVA >= pSectionHeader[i].VirtualAddress && | ||
RVA < pSectionHeader[i].VirtualAddress + | ||
pSectionHeader[i].Misc.VirtualSize) | ||
{ | ||
return (RVA - pSectionHeader[i].VirtualAddress + | ||
pSectionHeader[i].PointerToRawData); | ||
} | ||
} | ||
|
||
EXIT_ERROR("rva to foa failure!"); | ||
} | ||
|
||
DWORD FOA_TO_RVA(LPVOID pFileBuffer, PIMAGE_DOS_HEADER pDosHeader, | ||
PIMAGE_NT_HEADERS32 pNTHeader, | ||
PIMAGE_SECTION_HEADER pSectionHeader, IN DWORD FOA) | ||
{ | ||
if (FOA < pNTHeader->OptionalHeader.SizeOfHeaders) | ||
return FOA; | ||
|
||
for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++) | ||
{ | ||
if (FOA >= pSectionHeader[i].PointerToRawData && | ||
FOA < pSectionHeader[i].PointerToRawData + | ||
pSectionHeader[i].Misc.VirtualSize) | ||
{ | ||
return (FOA - pSectionHeader[i].PointerToRawData + | ||
pSectionHeader[i].VirtualAddress); | ||
} | ||
} | ||
|
||
EXIT_ERROR("foa to rva error!"); | ||
} |
Oops, something went wrong.