向PE文件中添加ShellCode

最烦打代码了,但是貌似代码是最高效的方式……


之前手动往PE文件中注入代码添加ShellCode,最近手动往PE文件中注入代码,貌似就是捆绑吧………………


 
  
1
------------------------------------------ 线------------------------------------------

   工具:一个想添加ShellCode的程序,VS2013

步骤为VS中的注释

-/******************************************************************************************/
//步骤分为五个 */
//1,将文件读取到缓冲区,用pFileBuffer接收吗,构造ShellCode(); */
//2,根据对齐的情况来,将接收的FileBuffer 手动转换为ImageBuffer; */
//3,向已经转换完成的ImageBuffer的代码空白区; */
//4,补充完ShellCode; */
//5,更改OEP; */
/*******************************************************************************************/

ps:貌似PE文件的类型在这两个头文件中

#include
#include

这里我用的程序是win自带的notepad;

首先将文件读入缓冲区;

 1  
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
DWORDReadPEFile(INLPSTRlpszFile,OUTLPVOID*FileBuffer)
{
FILE*pFile=NULL;
DWORDfileSize=0;
//
LPVOIDpFileBuffer=NULL;
//
fopen_s(&pFile,lpszFile,"rb");
if(!pFile)
{
printf("EXE!");
returnNULL;
}
else
{
printf("Successful!\n");
}
//
fseek(pFile,0,SEEK_END);
fileSize=ftell(pFile);
fseek(pFile,0,SEEK_SET);
//
pFileBuffer=malloc(fileSize);
if(!pFileBuffer)
{
printf("!");
fclose(pFile);
returnNULL;
}
//
size_tn=fread(pFileBuffer,fileSize,1,pFile);
if(!n)
{
printf("!");
free(pFileBuffer);
fclose(pFile);
returnNULL;
}
//
*FileBuffer=pFileBuffer;
fclose(pFile);
pFileBuffer=NULL;
returnfileSize;
};

这个是单独的函数路径是在头文件中定义的,将文件读到内存中之后用FileBuffer接收。返回的文件的长度,注意的地方是要把在本函数中使用的空间最后变为NULL;这个时候的数据是按文件对齐排列在内存中的,需要把文件对齐拉伸为内存对齐。

第二个函数为FileBufferToImageBuffer;文件对齐转换为内存对齐,起始位置的地址从0转换为ImageBase;

 
  
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
DWORD FileBufferToImageBuffer ( IN LPVOID pFileBuffer , OUT LPVOID * pImageBuffer ) {
//
PIMAGE_DOS_HEADER pDosHeader = NULL ;
PIMAGE_NT_HEADERS pNTHeader = NULL ;
PIMAGE_FILE_HEADER pPEHeader = NULL ;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL ;
PIMAGE_SECTION_HEADER pSectionHeader = NULL ;
LPVOID pTempImageBuffer = NULL ;
//
if ( pFileBuffer == NULL )
{
printf ( " \n " ) ;
return 0 ;
}
//
if ( * (( PWORD ) pFileBuffer ) != IMAGE_DOS_SIGNATURE ) {
printf ( " MZ \n " ) ;
return 0 ;
}
pDosHeader = ( PIMAGE_DOS_HEADER ) pFileBuffer ;
if ( * (( PWORD ) (( DWORD ) pFileBuffer + pDosHeader -> e_lfanew )) != IMAGE_NT_SIGNATURE ) {
printf ( " PE \n " ) ;
return 0 ;
}
printf ( " %x\n " , pFileBuffer ) ;
//NT
pNTHeader = ( PIMAGE_NT_HEADERS ) (( DWORD ) pFileBuffer + pDosHeader -> e_lfanew ) ;
//PE
pPEHeader = ( PIMAGE_FILE_HEADER ) ((( DWORD ) pNTHeader ) + 4 ) ;
//PE
pOptionalHeader = ( PIMAGE_OPTIONAL_HEADER ) (( DWORD ) pPEHeader + IMAGE_SIZEOF_FILE_HEADER ) ;
//
pSectionHeader = ( PIMAGE_SECTION_HEADER ) (( DWORD ) pOptionalHeader + pPEHeader -> SizeOfOptionalHeader ) ;
//
pTempImageBuffer = malloc ( pOptionalHeader -> SizeOfImage ) ;
printf ( " %x\n " , pTempImageBuffer ) ;
if ( ! pTempImageBuffer ) {
printf ( " \n " ) ;
return 0 ;
}
//
memset ( pTempImageBuffer , 0 , pOptionalHeader -> SizeOfImage ) ;
//TempImageBuffer0
memcpy ( pTempImageBuffer , pDosHeader , pOptionalHeader -> SizeOfHeaders ) ;
PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader ;
// FileBuffer-ImageBuffer
for ( int i = 0 ; i < pPEHeader -> NumberOfSections ; i ++ , ptempSectionHeader ++ ) { //
memcpy (
( void * ) (( DWORD ) pTempImageBuffer + ptempSectionHeader -> VirtualAddress ) , //
( void * ) (( DWORD ) pDosHeader + ptempSectionHeader -> PointerToRawData ) , //
ptempSectionHeader -> SizeOfRawData ) ;
}
* pImageBuffer = pTempImageBuffer ;
pTempImageBuffer = NULL ;
PIMAGE_DOS_HEADER PDosHeader = NULL ;
return pOptionalHeader -> SizeOfImage ;
}

转换时需要先复制头信息,节表信息,PE文件头部没有对齐 只是起始位置改变。当复制节表表示的内容时需要每个节每个节填充;

这个地方需要注意RVA ROA FOA一些乱七八糟的概念;

FileBuffer转换为ImageBuffer之后就可以添加ShellCode了,这个地方用到一个概念,需要先把让OEP指向ShellCode然后再跳转回到原始OEP执行原始代码;代码如下

 
  
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
VOID TestAddCode ( ) {
BYTE ShellCode [ ] = {
0x6A , 00 , 0x6A , 00 , 0x6A , 00 , 0x6A , 00 ,
0xE8 , 00 , 00 , 00 , 00 ,
0xE9 , 00 , 00 , 00 , 00
} ;
LPVOID pFileBuffer ;
LPVOID pImageBuffer ;
LPVOID pNewBuffer ;
PIMAGE_DOS_HEADER pDosHeader = NULL ;
PIMAGE_NT_HEADERS pNTHeader = NULL ;
PIMAGE_FILE_HEADER pPEHeader = NULL ;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL ;
PIMAGE_SECTION_HEADER pSectionHeader = NULL ;
PBYTE codeBegin = NULL ;
BOOL isOK = FALSE ;
DWORD size = 0 ;
//
ReadPEFile ( INFILEPATH , & pFileBuffer ) ;
if ( ! pFileBuffer ) {
printf ( " \n " ) ;
free ( pFileBuffer ) ;
return ;
}
//
FileBufferToImageBuffer ( pFileBuffer , & pImageBuffer ) ;
printf ( " " ) ;
if ( ! pImageBuffer ) {
printf ( " FileBuffer to ImageBuffer false! \n " ) ;
free ( pFileBuffer ) ;
free ( pImageBuffer ) ;
return ;
}
//
pDosHeader = ( PIMAGE_DOS_HEADER ) pImageBuffer ;
pNTHeader = ( PIMAGE_NT_HEADERS ) (( DWORD ) pImageBuffer + pDosHeader -> e_lfanew ) ;
//PE
pPEHeader = ( PIMAGE_FILE_HEADER ) ((( DWORD ) pNTHeader ) + 4 ) ;
//PE
pOptionalHeader = ( PIMAGE_OPTIONAL_HEADER ) (( DWORD ) pPEHeader + IMAGE_SIZEOF_FILE_HEADER ) ;
//
pSectionHeader = ( PIMAGE_SECTION_HEADER ) (( DWORD ) pOptionalHeader + pPEHeader -> SizeOfOptionalHeader ) ;
if ((( pSectionHeader -> SizeOfRawData ) - ( pSectionHeader -> Misc . VirtualSize )) < SHELLCODELENGTH ) {
printf ( " \n " ) ;
free ( pImageBuffer ) ;
free ( pFileBuffer ) ;
return ;
}
codeBegin = ( PBYTE ) (( DWORD ) pImageBuffer + pSectionHeader -> VirtualAddress + pSectionHeader -> Misc . VirtualSize
         ) ;
memcpy ( codeBegin , ShellCode , SHELLCODELENGTH ) ;
//E8
DWORD callAddr = ( MESSAGEBOXADDR - ( pOptionalHeader -> ImageBase ) + ((( DWORD ) codeBegin + 0xD - ( DWORD
         ) pImageBuffer ))) ;
* ( PDWORD ) ( codeBegin + 9 ) = callAddr ;
//E9
DWORD jmpAddr = (( pOptionalHeader -> ImageBase + pOptionalHeader -> AddressOfEntryPoint ) - ( pOptionalHeader
         -> ImageBase + (( DWORD ) codeBegin + SHELLCODELENGTH ))) ;
* ( PDWORD ) ( codeBegin + 0xE ) = jmpAddr ;
//OEP
pOptionalHeader -> AddressOfEntryPoint = ( DWORD ) codeBegin - ( DWORD ) pImageBuffer ;
size = ImageBufferToNewBuffer ( pImageBuffer , & pNewBuffer ) ;
if ( size == 0 || ! pNewBuffer ) {
printf ( " imagebuffer->newBuffer false! \n " ) ;
free ( pFileBuffer ) ;
free ( pImageBuffer ) ;
free ( pNewBuffer ) ;
return ;
}
PIMAGE_DOS_HEADER pDosHeader_new = NULL ;
pDosHeader_new = ( PIMAGE_DOS_HEADER ) pNewBuffer ;
printf ( " %s\n " , pDosHeader_new ) ;
isOK = SaveFile ( pNewBuffer , size , OUTFILEPATH ) ;
if ( isOK ) {
printf ( " \n %s\n " , OUTFILEPATH ) ;
free ( pFileBuffer ) ;
free ( pImageBuffer ) ;
free ( pNewBuffer ) ;
}
}

每个函数都有独立的功能,貌似就是那六个字:高内聚,低耦合;

这里是将ShellCode存放在一个数组中然后直接将数组整体添加到应该添加的地方。

剩下的就是将已经添加过ShellCode的文件从内存对齐状态转换为文件对齐,然后保存文件,这个是之前从FileBuffer转换成ImageBuffer的逆过程;

就不添加代码了,太多了。



感谢滴水逆向的教程。

你可能感兴趣的:(PE)