实现自加自写壳

提取文件为数据流,加密后装载在解壳文件区块中,解壳文件加载区块中的加密数据流解密,PELoader加载即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Exception.h
#pragma once
#include <windows.h>
#include <stdio.h>
#define MY_EXCEPTION_ERROR 0x20060702

enum MY_ERR {
MYERR_ARGC = 0xAC,
MYERR_FOPEN = 0xE,
MYERR_CALLOC = 0xCA,
MYERR_READ = 0xEA,
MYERR_OPENFUN = 0xEF,
};
LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo);
void ThrowMyError(DWORD errcode);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//section.h
#pragma once
#include<Windows.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<stdint.h>
//打印节区表信息
void PrintSec(PIMAGE_SECTION_HEADER pSec);
//*********************************
//传入参数:32位下Nt头指针, 节区大小
//返回值:新建节区表指针
//*********************************
PIMAGE_SECTION_HEADER MakeNewSec32(PBYTE pBuffer, int SecSize);
//*********************************
//传入参数:64位下Nt头指针, 节区大小
//返回值:新建节区表指针
//*********************************
PIMAGE_SECTION_HEADER MakeNewSec64(PBYTE pBuffer, int SecSize);
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
//source.h
#pragma once
#include<Windows.h>
#include<string.h>
#include <stdlib.h>
#include<stdio.h>
typedef struct file
{
PBYTE pBuffer;
DWORD fSize;
}FileStruct, * pFileStruct;
//传入文件路径,返回文件所在最后一层文件夹路径
PCHAR GetTargetFolder(PCHAR fullPath);
//传入文件夹路径与文件名, 返回文件夹下文件名路径
PCHAR MakeOutNameInFolder(const char* folder, const char* filename);
//打开目标路径文件, 返回指针大小结构体指针
pFileStruct OpenPathFileA(PCHAR PathName);
//打开目标路径文件且规定大小, 返回指针大小结构体指针
pFileStruct OpenPathFileAddSizeA(PCHAR PathName, int size);
//写入文件
void OpenAndWrite(PCHAR Path, pFileStruct AFile);

char* MakeFullPathRelativeToExe(const char* relativePath);

void PrintFileStruct(pFileStruct a);
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
#include <Windows.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "section.h"
#include "source.h"
#include "Exception.h"
//壳加密函数
void EnPacker(PBYTE test, DWORD size)
{
for (int i = 0; i < size; i++)
{
test[i] = (test[i] & 0xf0) | ((((test[i] >> 4) & 0x0f) + (test[i] & 0x0f)) & 0x0f);
}
}

//长度为参数3的数组参数2写入参数1中
void WriteBySize(PBYTE pBuffer, PBYTE pWriten, DWORD size)
{
__try
{
for (int i = 0; i < size; i++)
{
pBuffer[i] = pWriten[i];
}
}
__except (1)
{
CHAR ERR[50] = { 0 };
DWORD e = GetLastError();
sprintf_s(ERR, "WriteBySize错误\n错误码:0x%08x", e);
MessageBoxA(NULL, ERR, "by l1pmoluy", MB_OK);
}
}

int main(int argc, const char** argv, const char** envp)
{
__try
{
PVOID h = AddVectoredExceptionHandler(1, VectoredHandler);
if (!h) {
printf("AddVectoredExceptionHandler failed\n");
return 1;
}
if (argc < 2)
{
ThrowMyError(MYERR_ARGC);
return 0;
}
PCHAR BePackeredPath = (PCHAR)argv[1];
//PCHAR BePackeredPath = (PCHAR)"E:\\download\\Click_to_win.exe";

pFileStruct pBePackered = OpenPathFileA(BePackeredPath);

DWORD Wei = PIMAGE_NT_HEADERS(pBePackered->pBuffer + PIMAGE_DOS_HEADER(pBePackered->pBuffer)->e_lfanew)->OptionalHeader.Magic;
PIMAGE_SECTION_HEADER pNewSec = NULL;
PCHAR bFolderTemplated = NULL;
pFileStruct pTemplate = NULL;
PCHAR TemplatePath = NULL;
PCHAR bOutPath = NULL;

//壳加密
EnPacker(pBePackered->pBuffer, pBePackered->fSize);

if (Wei == 0x10B)
{
//打开模板
TemplatePath = (PCHAR)MakeFullPathRelativeToExe("template\\template32.exe");
pTemplate = OpenPathFileAddSizeA(TemplatePath, pBePackered->fSize);
if (pTemplate == NULL)
{
ThrowMyError(MYERR_OPENFUN);
}
//创建节区
pNewSec = MakeNewSec32(pTemplate->pBuffer, pBePackered->fSize);
printf("32!\n");
}
else if (Wei == 0x20B)
{
//打开模板
TemplatePath = (PCHAR)MakeFullPathRelativeToExe("template\\template64.exe");
pTemplate = OpenPathFileAddSizeA(TemplatePath, pBePackered->fSize);
if (pTemplate == NULL)
{
ThrowMyError(MYERR_OPENFUN);
}
//创建节区
pNewSec = MakeNewSec64(pTemplate->pBuffer, pBePackered->fSize);
printf("64!\n");
}

//写入节区
WriteBySize(pTemplate->pBuffer + pNewSec->PointerToRawData, pBePackered->pBuffer, pBePackered->fSize);
//获取输出路径
bFolderTemplated = GetTargetFolder(BePackeredPath);
bOutPath = MakeOutNameInFolder(bFolderTemplated, "My_Packer.exe");
OpenAndWrite(bOutPath, pTemplate);
//最终提示
MessageBoxA(NULL, bOutPath, "by l1pmoluy", MB_OK);

return 0;
}
__except(1)
{
printf("%08x\n", GetLastError());
system("pause");
}
}
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
//Exception.cpp
#include "Exception.h"
LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
DWORD code = ExceptionInfo->ExceptionRecord->ExceptionCode;
if (code == MY_EXCEPTION_ERROR) {
ULONG_PTR errcode = 0;
if (ExceptionInfo->ExceptionRecord->NumberParameters >= 1)
errcode = ExceptionInfo->ExceptionRecord->ExceptionInformation[0];

CHAR ERR[50] = { 0 };
DWORD e;
switch ((unsigned int)errcode) {
case MYERR_ARGC:
memcpy(ERR, "使用方法: Ipacker.exe <文件路径> or 拖文件在Ipacker上", 55);
break;
case MYERR_FOPEN:
e = GetLastError();
sprintf_s(ERR, "fopen_s错误\n错误码:0x%08x", e);
break;
case MYERR_READ:
e = GetLastError();
sprintf_s(ERR, "fread错误\n错误码:0x%08x", e);
break;
case MYERR_CALLOC:
e = GetLastError();
sprintf_s(ERR, "calloc错误\n错误码:0x%08x", e);
break;
case MYERR_OPENFUN:
memcpy(ERR, "Error in openfile function!", 28);
break;
default:
memcpy(ERR, "未知错误", 9);
break;

}
MessageBoxA(NULL, ERR, "by l1pmoluy", MB_OK);
ExitProcess((UINT)errcode);
}
return EXCEPTION_CONTINUE_SEARCH;
}

void ThrowMyError(DWORD errcode)
{
ULONG_PTR info[1];
info[0] = errcode;
RaiseException(MY_EXCEPTION_ERROR, 0, 1, info);
}
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
//section.cpp
#include"section.h"
#include "Exception.h"

//打印节区表信息
void PrintSec(PIMAGE_SECTION_HEADER pSec)
{
printf("============Section:%s=============\n", pSec->Name);
printf("VirtualAddress: %x\n", pSec->VirtualAddress);
printf("VirtualSize: %x\n", pSec->Misc.VirtualSize);
printf("PointerToRawData: %x\n", pSec->PointerToRawData);
printf("SizeOfRawData: %x\n", pSec->SizeOfRawData);
printf("Characteristics: %x\n", pSec->Characteristics);
printf("\n");
}

//参数1向参数2为单位上取整
long long AlignUp(long long x, long long base)
{
return ((x + base - 1) / base) * base;
}

//*********************************
//传入参数:32位下Nt头指针, 节区大小
//返回值:新建节区表指针
//*********************************
PIMAGE_SECTION_HEADER MakeNewSec32(PBYTE pBuffer, int SecSize)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuffer;
PIMAGE_NT_HEADERS32 pNt = (PIMAGE_NT_HEADERS32)(pBuffer + pDos->e_lfanew);
PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((LPBYTE)pNt + sizeof(IMAGE_NT_HEADERS32));
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER) & (pNt->FileHeader);

PWORD SecNum = &(pFileHeader->NumberOfSections);

for (int i = 0; i < pFileHeader->NumberOfSections; i++)
{
pSec++;
}

PIMAGE_SECTION_HEADER pLastSec = (pSec - 1);

//创建节区
pFileHeader->NumberOfSections++;
memset(pSec, 0, sizeof(IMAGE_SECTION_HEADER));
memcpy(pSec->Name, ".Packer", strlen(".Packer"));
//位置确定
pSec->PointerToRawData = AlignUp(pLastSec->PointerToRawData + pLastSec->SizeOfRawData, pNt->OptionalHeader.FileAlignment);
pSec->VirtualAddress = AlignUp(pLastSec->VirtualAddress + pLastSec->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
//节区操作
pSec->SizeOfRawData = AlignUp(SecSize, pNt->OptionalHeader.FileAlignment);
pSec->Misc.VirtualSize = AlignUp(SecSize, pNt->OptionalHeader.SectionAlignment);
pSec->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
//更新文件大小
pNt->OptionalHeader.SizeOfImage = AlignUp(pSec->VirtualAddress + pSec->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
return pSec;
}

//*********************************
//传入参数:64位下Nt头指针, 节区大小
//返回值:新建节区表指针
//*********************************
PIMAGE_SECTION_HEADER MakeNewSec64(PBYTE pBuffer, int SecSize)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuffer;
PIMAGE_NT_HEADERS64 pNt = (PIMAGE_NT_HEADERS64)(pBuffer + pDos->e_lfanew);
PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((LPBYTE)pNt + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNt->FileHeader.SizeOfOptionalHeader);
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER) & (pNt->FileHeader);

PWORD SecNum = &(pFileHeader->NumberOfSections);

for (int i = 0; i < pFileHeader->NumberOfSections; i++)
{
pSec++;
}

PIMAGE_SECTION_HEADER pLastSec = (pSec - 1);

//创建节区
pFileHeader->NumberOfSections++;
memset(pSec, 0, sizeof(IMAGE_SECTION_HEADER));
memcpy(pSec->Name, ".Packer", strlen(".Packer"));
//位置确定
pSec->PointerToRawData = AlignUp(pLastSec->PointerToRawData + pLastSec->SizeOfRawData, pNt->OptionalHeader.FileAlignment);
pSec->VirtualAddress = AlignUp(pLastSec->VirtualAddress + pLastSec->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
//节区操作
pSec->SizeOfRawData = AlignUp(SecSize, pNt->OptionalHeader.FileAlignment);
pSec->Misc.VirtualSize = AlignUp(SecSize, pNt->OptionalHeader.SectionAlignment);
pSec->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
//更新文件大小
pNt->OptionalHeader.SizeOfImage = AlignUp(pSec->VirtualAddress + pSec->Misc.VirtualSize, pNt->OptionalHeader.SectionAlignment);
return pSec;
}
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
//source.cpp
#include"source.h"
#include"Exception.h"
static int is_absolute_path_windows(const char* p)
{
if (!p || !p[0]) return 0;
// 形如 "C:\..." 或 "C:/..."
if (strlen(p) >= 2 && ((p[1] == ':' && ((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')))))
return 1;
// UNC 路径 \\server\share 或以 '\' 开头的绝对路径
if (p[0] == '\\' || p[0] == '/')
return 1;
return 0;
}

char* MakeFullPathRelativeToExe(const char* relativePath)
{
if (!relativePath) return NULL;

// 如果已经是绝对路径,直接返回其 strdup(caller free)
if (is_absolute_path_windows(relativePath)) {
size_t L = strlen(relativePath) + 1;
char* out = (char*)malloc(L);
if (!out) return NULL;
memcpy(out, relativePath, L);
return out;
}

// 获取可执行文件完整路径
char exePath[MAX_PATH];
DWORD len = GetModuleFileNameA(NULL, exePath, MAX_PATH);
if (len == 0 || len == MAX_PATH) {
// 失败或路径过长(可扩展为宽字符和 \\?\ 前缀)
return NULL;
}

// 找到最后一个反斜杠,保留目录(包含末尾的 '\')
char* last = strrchr(exePath, '\\');
size_t dirLen;
if (last) dirLen = (size_t)(last - exePath) + 1;
else dirLen = strlen(exePath); // 极少见情况

size_t relLen = strlen(relativePath);
size_t need = dirLen + relLen + 1;
char* full = (char*)malloc(need);
if (!full) return NULL;

// 复制目录并拼接相对路径
memcpy(full, exePath, dirLen);
full[dirLen] = '\0';
// 如果 relativePath 以 '\' 或 '/' 开头,避免产生重复分隔符
if ((relativePath[0] == '\\' || relativePath[0] == '/') && dirLen > 0 && (full[dirLen - 1] == '\\' || full[dirLen - 1] == '/')) {
// 移动一位,跳过 relativePath 的首字符
strncat_s(full, need, relativePath + 1, relLen - 1);
}
else {
strncat_s(full, need, relativePath, relLen);
}

return full; // caller must free()
}
PCHAR GetTargetFolder(PCHAR fullPath)
{
if (!fullPath) return NULL;

// 找到最后一个 '\' 或 '/'
const char* last_bslash = strrchr(fullPath, '\\');
const char* last_slash = strrchr(fullPath, '/');

const char* last_sep = NULL;
if (last_bslash && last_slash)
last_sep = (last_bslash > last_slash) ? last_bslash : last_slash;
else if (last_bslash)
last_sep = last_bslash;
else
last_sep = last_slash;

if (!last_sep) {
// 没有分隔符,返回当前目录标识 "./"
PCHAR res = (PCHAR)malloc(3);
if (!res) return NULL;
strcpy(res, "./");
return res;
}

// 目录长度包含分隔符本身
size_t len = (size_t)(last_sep - fullPath) + 1; // +1 包含分隔符
PCHAR folder = (PCHAR)malloc(len + 1); // 额外 +1 放终止符
if (!folder) return NULL;

memcpy(folder, fullPath, len);
folder[len] = '\0';
return folder;
}

PCHAR MakeOutNameInFolder(const char* folder, const char* filename)
{
if (!folder || !filename) return NULL;

size_t folder_len = strlen(folder);
size_t file_len = strlen(filename);

// 判断 folder 是否以路径分隔符结尾(支持 '\' 或 '/')
int has_sep = 0;
if (folder_len > 0) {
char last = folder[folder_len - 1];
if (last == '\\' || last == '/') has_sep = 1;
}

// 目标长度 = folder_len + (可能的分隔符1) + file_len + 终止符
size_t total = folder_len + (has_sep ? 0 : 1) + file_len + 1;
PCHAR out = (PCHAR)malloc(total);
if (!out) return NULL;

// 复制 folder
memcpy(out, folder, folder_len);

// 若没有分隔符则插入 '\'
size_t pos = folder_len;
if (!has_sep) {
out[pos++] = '\\'; // 使用反斜杠作为默认分隔符(Windows)
}

// 复制文件名并以 '\0' 结束
memcpy(out + pos, filename, file_len);
out[pos + file_len] = '\0';

return out;
}

pFileStruct OpenPathFileA(PCHAR PathName)
{
FILE* pFile;
DWORD fSize;
DWORD RealSize = 0;
PBYTE pBuffer = NULL;
pFileStruct AFile = NULL;
if(fopen_s(&pFile, PathName, "rb"))
{
ThrowMyError(MYERR_FOPEN);
}

fseek(pFile, NULL, SEEK_END);
fSize = ftell(pFile);
fseek(pFile, NULL, SEEK_SET);

pBuffer = (PBYTE)calloc(fSize, 1);

if (!pBuffer)
{
ThrowMyError(MYERR_CALLOC);
}

RealSize = fread(pBuffer, 1, fSize, pFile);
fclose(pFile);

if (RealSize != fSize)
{
ThrowMyError(MYERR_READ);
}

AFile = (pFileStruct)calloc(sizeof(FileStruct), 1);

if (!AFile)
{
ThrowMyError(MYERR_CALLOC);
}
AFile->pBuffer = pBuffer;
AFile->fSize = fSize;
return AFile;
}

pFileStruct OpenPathFileAddSizeA(PCHAR PathName, int size)
{
FILE* pFile;
DWORD fSize;
DWORD RealSize = 0;
PBYTE pBuffer = NULL;
pFileStruct AFile = NULL;
if (fopen_s(&pFile, PathName, "rb"))
{
ThrowMyError(MYERR_FOPEN);
}

fseek(pFile, NULL, SEEK_END);
fSize = ftell(pFile);
fseek(pFile, NULL, SEEK_SET);

pBuffer = (PBYTE)calloc(fSize + size, 1);

if (!pBuffer)
{
ThrowMyError(MYERR_CALLOC);
}

RealSize = fread(pBuffer, 1, fSize, pFile);
fclose(pFile);

if (RealSize != fSize)
{
ThrowMyError(MYERR_READ);
}

AFile = (pFileStruct)calloc(sizeof(FileStruct), 1);

if (!AFile)
{
ThrowMyError(MYERR_CALLOC);
}
AFile->pBuffer = pBuffer;
AFile->fSize = (fSize + size);
return AFile;
}

void OpenAndWrite(PCHAR Path, pFileStruct AFile)
{
FILE* pFile;
fopen_s(&pFile, Path, "wb");
fwrite(AFile->pBuffer, 1, AFile->fSize, pFile);
}

void PrintFileStruct(pFileStruct a)
{
printf("Buffer: %x\n", a->pBuffer);
printf("Size: %x\n", a->fSize);
return;
}