Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
smallzhong committed Aug 18, 2020
1 parent 3d583e6 commit 3e078a2
Show file tree
Hide file tree
Showing 33 changed files with 1,233 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .gitignore
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
59 changes: 59 additions & 0 deletions README.md
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)项目中的代码
200 changes: 200 additions & 0 deletions 加壳机/12312412512r2r12.cpp
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!");
}
Loading

0 comments on commit 3e078a2

Please sign in to comment.