简单的基于壳的变形壳工具

起初写这个简单工具的想法是由原来出一道CTF题目时,对upx壳进行简单变形后,让peid和exeinfoPe无法识别,从而对逆向者在静态分析上增加一定难度写的。但是在写的过程中发现,其实对专业的逆向从业者似乎并不能产生很好的作用,对于熟悉一些基本壳的大牛们,这个工具写了和没写没什么太大的区别。但是由于已经写了那么一点了,索性就写完再说,本来一开始的想法是从静态库中提取多种基本壳的签名,然后对一类壳进行一种变换,这样每一种基本壳也就都有了一种简单的变形壳的,发现价值不大,最终也就写了一个识别upx然后变形的壳,丢上来,哪天代码不见了,也好找,2333,至少也是花了一星期时间的呢!
工具思路:1.识别基本壳的类型 2.根据壳类型,选择不同的变换方式(只写了upx壳)

upx变换方式:1.抹去dos stub Program 2.含有upx的字符串全部替代 3.节表的节名称均修改为正常的.text.rdata等 4.抹去upx特征码 5.增加一个节区(相应地,也要增加一个节表),将入口地址引向新节区,在新节区添加代码,最后实现跳转。(仅用于测试,所以新节区代码很简单,没有反调试,混淆,花指令之类的东西)

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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
//main.cpp
#include<stdio.h>
#include<string.h>
#include<Windows.h>
#include<stdlib.h>
#include"compare.h"
#include<stdio.h>

PBYTE realEntryPoint;

//**************copy file****************
char *myCopyFile(char *pExistingFile,char *pNewFile)
{
char *pFileName = pNewFile;
strcpy(pFileName, pExistingFile);
strcat(pFileName, "_new");
CopyFileA(pExistingFile, pFileName, FALSE);
return pFileName;
}
//**************copy file****************

BOOL isPEFormat(PBYTE pFile)
{
PBYTE my_PE = pFile;
if (my_PE[0] == 'M' && my_PE[1] == 'Z')
{
my_PE += 0x3C;
my_PE = pFile + *(DWORD *)my_PE;
if (my_PE[0] == 'P' && my_PE[1] == 'E')
{
wprintf(L"GOOD! This is a PE File!\n");
return TRUE;
}
}
return FALSE;
}

void editWays(int packMethods, PBYTE pFile)
{
/***************move PEHeader to dosHeader**************/
char *sectionName[9] = { ".text",".rdata",".data",".idata",".pdata",".tls",".gfids",".rsrc",".reloc" };
PBYTE dosHeader = pFile + 0x40;
PBYTE my_PE = pFile + *(DWORD *)(pFile + 0x3C);
WORD numOfSectionTable = *(WORD *)(my_PE + 4 + 2);
DWORD peHeaderSize = 4 + 0x14 + +0xE0 + 0x28 * numOfSectionTable;
memcpy(dosHeader, my_PE, peHeaderSize);
PBYTE sectionTable = my_PE + 4 + 0x14 + 0xE0;
PBYTE firstSectionPosition = pFile + *(DWORD *)(sectionTable + 20);
PBYTE newPosition = dosHeader + peHeaderSize;
PBYTE newSectionTable;
do
{
newPosition[0] = '\0';
newPosition += 1;
} while (firstSectionPosition != newPosition);
/***************move PEHeader to dosHeader**************/

/*edit mark that directs to PE*/
*(DWORD *)(pFile + 0x3C) = (DWORD)0x40;
/*edit mark that directs to PE*/
my_PE = pFile + *(DWORD *)(pFile + 0x3C);
sectionTable = my_PE + 4 + 0x14 + 0xE0;
DWORD addressOfEntryPoint;
DWORD newRVA;
DWORD newRawOffset;
BYTE dynamicMark;
switch (packMethods)
{
case 0:
/*edit section name*/
newSectionTable = sectionTable - 0x28;
for (int i = 0; i < numOfSectionTable; i++)
{
newSectionTable += 0x28;
memcpy(newSectionTable, sectionName[i], strlen(sectionName[i]));
}
/*edit section name*/

/*edit entrypoint signature*/
realEntryPoint[0] = 0x90;
/*edit entrypoint signature*/

/********************set characters******************/
newRVA = *(DWORD *)(newSectionTable + 12) + *(DWORD *)(newSectionTable + 8);
newRawOffset = *(DWORD *)(newSectionTable + 16) + *(DWORD *)(newSectionTable + 20);
newSectionTable += 0x28;
memcpy(newSectionTable, sectionName[7], strlen(sectionName[7]));
*(DWORD *)(newSectionTable + 8) = (DWORD)0x1000;
*(DWORD *)(newSectionTable + 12) = (DWORD)newRVA;
*(DWORD *)(newSectionTable + 16) = (DWORD)0x200;
*(DWORD *)(newSectionTable + 20) = (DWORD)newRawOffset;
*(DWORD *)(newSectionTable + 24) = *(DWORD *)(newSectionTable + 28) = *(DWORD *)(newSectionTable + 32) = (DWORD)0x0;
*(DWORD *)(newSectionTable + 36) = (DWORD)0xE0000020;
/*increase a section*/
*(WORD *)(my_PE + 4 + 2) = numOfSectionTable + 1;
/*increase a section*/

/*edit size of image*/
*(DWORD *)(my_PE + 4 + 0x14 + 0x38) = *(DWORD *)(newSectionTable + 12) + *(DWORD *)(newSectionTable + 8);
printf("size of image:%X\n", *(DWORD *)(my_PE + 4 + 0x14 + 0x38));
/*edit size of image*/
/********************set characters******************/
addressOfEntryPoint = *(DWORD *)(my_PE + 4 + 0x14 + 0x10) + *(DWORD *)(my_PE + 4 + 0x14 + 0x1c);
memcpy(entryCode + 12, (DWORD *)&addressOfEntryPoint, 4);
memcpy((pFile + newRawOffset), entryCode, 17);
/*Reset addressOfEntryPoint*/
*(DWORD *)(my_PE + 4 + 0x14 + 0x10) = (DWORD)newRVA;
dynamicMark = *(BYTE *)(my_PE + 4 + 0x14 + 0x46);
if (dynamicMark == 0x40)
{
*(BYTE *)(my_PE + 4 + 0x14 + 0x46) = '\x00';
}
break;
default:
break;
}


}

int comparePackWays(PBYTE pEntryPoint)
{
int method,i,j;
method = i = j = 0;
BOOL find = FALSE;
for (i = 0; i < numOfPackMethod; i++)
{
for (j = 0; j < pack[i].signature_Length; j++)
{
if (!(pEntryPoint[j] == pack[i].signature[j] || pack[i].signature[j] == '?'))
{
wprintf(L"Not the %s\n", pack[i].packName);
break;
}
}
if (j == pack[i].signature_Length)
{
wprintf(L"%s packing!\n", pack[i].packName);
method = i;
find = TRUE;
break;
}
}
if (!find)
{
wprintf(L"Can't find packing match with this program!\n");
method = -1;
}
return method;
}

int checkPackWays(PBYTE pFile)
{
PBYTE my_PE = pFile;
my_PE += 0x3C;
my_PE = pFile + *(DWORD *)my_PE;
/*PE*/
DWORD adddressOfEntryPoint = *(DWORD *)(my_PE + 4 + 0x14 + 16);
/*address of entry point*/
printf("addressOfEntryPoint:%X\n", adddressOfEntryPoint);
WORD numOfSectionTable = *(WORD *)(my_PE + 4 + 2);
/*num of Section Table*/

PBYTE sectionTable = my_PE + 4 + 0x14 + 0xE0;
/*the position of sectionTable*/

DWORD RVA1,RVA2,fileOffset,rawEntryPoint;
RVA1 = RVA2 = fileOffset = rawEntryPoint = 0;
for (int i = 1; i <= numOfSectionTable; i++)
{
RVA1 = *(DWORD *)(sectionTable + 12);
RVA2 = *(DWORD *)(sectionTable + 0x28 + 12);
if (adddressOfEntryPoint >= RVA1 && adddressOfEntryPoint < RVA2)
{
fileOffset = adddressOfEntryPoint - RVA1;
rawEntryPoint = fileOffset + *(DWORD *)(sectionTable + 20);
break;
}
sectionTable += 0x28;
if (i == (numOfSectionTable - 1))
{
RVA1 = *(DWORD *)(sectionTable + 12);
fileOffset = adddressOfEntryPoint - RVA1;
rawEntryPoint = fileOffset + *(DWORD *)(sectionTable + 20);
break;
}
}
printf("rawEntryPoint:%X\n", rawEntryPoint);
realEntryPoint = rawEntryPoint + pFile;
int ways = comparePackWays(realEntryPoint);
printf("packWays:%d\n", ways);
return ways;
}

/**************MappingFileToMemory*******/
int myMappingFileToMemory(char *pFileName)
{
HANDLE hNewFile = NULL;
HANDLE hFileMap = NULL;

hNewFile = CreateFileA(pFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

if (hNewFile == INVALID_HANDLE_VALUE)
{
wprintf(L"CreateFileA Failed! Error code(%d)\n", GetLastError());
return 0;
}

DWORD dwFileSize = GetFileSize(hNewFile, NULL);

hFileMap = CreateFileMappingA(hNewFile, NULL, PAGE_READWRITE, 0, dwFileSize+0x200, NULL);

if (hFileMap == NULL)
{
wprintf(L"CreateFileMappingA Failed! Error code(%d)\n", GetLastError());
CloseHandle(hNewFile);
return 0;
}

PBYTE pFile = (PBYTE)MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);

if (pFile == NULL)
{
wprintf(L"MapViewOfFile Failed! Error code(%d)\n", GetLastError());
CloseHandle(hFileMap);
CloseHandle(hNewFile);
return 0;
}
/**************MappingFileToMemory*******/

/************************Check PE Format*******************/
BOOL isPE = isPEFormat(pFile);
if (!isPE)
{
wprintf(L"Please choose a PE format file!\n");
UnmapViewOfFile(pFile);
CloseHandle(hFileMap);
CloseHandle(hNewFile);
return 0;
}
/************************Check PE Format*******************/

/************************Check packing methods****************/
int packMethods = checkPackWays(pFile);
/************************Check packing methods****************/

/*******************edit shell******************/
editWays(packMethods, pFile);
/*******************edit shell******************/

// BYTE test[] = "Congratulations!hhhhhh";
// memcpy(pFile, test, sizeof(test));

UnmapViewOfFile(pFile);
CloseHandle(hFileMap);
CloseHandle(hNewFile);

return 0;
}


int main(int argc, TCHAR *argv[])
{
if (argc != 2)
{
wprintf(L"Please input two Parameters,one is the Pragram,another is the path which will be packed!\n");
return 0;
}

char pFileName[MAX_PATH] = { 0, };
// strcpy(pFileName, (char *)argv[1]);
// strcat(pFileName, "_new");
// CopyFileA((char *)argv[1], pFileName, FALSE);
myCopyFile((char *)argv[1],pFileName);
printf("%s\n", pFileName);
myMappingFileToMemory(pFileName);


return 0;
}

//compare.h
#include<stdio.h>
#include<string.h>

#define len 0x200
int numOfPackMethod = 1;


typedef struct
{
TCHAR *packName;
unsigned char signature[50];
int signature_Length;
}packMethod;

packMethod pack[] = { { L"upx",{ 0x60,0xBE,'?','?','?',0x00,0x8D,0xBE,'?','?','?',0xFF },12 } };
BYTE entryCode[len] = { 0x53, 0x53, 0x53, 0x5B, 0x5B, 0x83, 0xC4, 0x01, 0x83, 0xC4, 0xFF, 0x68 ,'?','?', '?', '?', 0xC3};

23333,简陋的工具,仅作个人想法的纪念!