首页
社区
课程
招聘
为PE文件增加新节,并在新节中增入SHELL CODE加载指定DLL
2006-12-17 00:03 27314

为PE文件增加新节,并在新节中增入SHELL CODE加载指定DLL

2006-12-17 00:03
27314
//add_section.cpp
#include "windows.h"
#include "stdio.h"
//判断文件是否为合法PE文件
BOOL CheckPe(FILE* pFile)
{               
        fseek(pFile,0,SEEK_SET);
        BOOL        bFlags=FALSE;
        WORD        IsMZ;
        DWORD        IsPE,pNT;
        fread(&IsMZ,sizeof(WORD),1,pFile);
        if(IsMZ==0x5A4D)
        {
                fseek(pFile,0x3c,SEEK_SET);
                fread(&pNT,sizeof(DWORD),1,pFile);
                fseek(pFile,pNT,SEEK_SET);
                fread(&IsPE,sizeof(DWORD),1,pFile);
                if(IsPE==0X00004550)
                        bFlags=TRUE;
                else
                        bFlags=FALSE;
        }
        else
                bFlags=FALSE;
        fseek(pFile,0,SEEK_SET);
        return bFlags;
}

//用来计算对齐数据后的大小
int alig(int size,unsigned int align)
{
        if(size%align!=0)
                return (size/align+1)*align;
        else
                return size;
}

int main(int argc,char* argv[])
{
        if(argc!=2)
        {
                printf("\t\tusage:add_section filename\n");
                exit(-1);
        }
        FILE* rwFile;
        if((rwFile=fopen(argv[1],"rb"))==NULL)//打开文件失败则退出
        {
                printf("\t\tOpen file faild\n");
                exit(-1);
        }

        if(!CheckPe(rwFile))
        {
                printf("\t\tinvalid pe......!\n");
                exit(-1);
        }
        //备份原文件
        char szNewFile[10]="_New.exe";
        if(!CopyFile(argv[1],szNewFile,0)) //若备份文件出错则退出
        {
                printf("\t\tbak faild\n");
                exit(-1);
        }
        IMAGE_NT_HEADERS NThea;
        fseek(rwFile,0x3c,0);
        DWORD pNT; //pNT中存放IMAGE_NT_HEADERS结构的地址
        fread(&pNT,sizeof(DWORD),1,rwFile);
        fseek(rwFile,pNT,0);
        fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile); //读取原文件的IMAGE_NT_HEADERS结构
        //保存原文件区块数量与OEP
        int nOldSectionNo=NThea.FileHeader.NumberOfSections;
        int OEP=NThea.OptionalHeader.AddressOfEntryPoint;
        //保存文件对齐值与区块对齐值
        int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment;
        int FILE_ALIG=NThea.OptionalHeader.FileAlignment;

        //定义要添加的区块
        IMAGE_SECTION_HEADER        NewSection;
        //将该结构全部清零
        memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));
        //再定义一个区块,来存放原文件最后一个区块的信息
        IMAGE_SECTION_HEADER SEChea;
        //读原文件最后一个区块的信息
        fseek(rwFile,pNT+248,0);
        for(int i=0;i<nOldSectionNo;i++)
                fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile);

        FILE *newfile=fopen(szNewFile,"rb+");
        if(newfile==NULL)
        {
                printf("\t\tOpen bak file faild\n");
                exit(-1);
        }
        fseek(newfile,SEChea.PointerToRawData+SEChea.SizeOfRawData,SEEK_SET);
        goto shellend;
__asm
{               
shell:        PUSHAD
                MOV        EAX,DWORD PTR FS:[30H]        ;FS:[30H]指向PEB
                MOV        EAX,DWORD PTR [EAX+0CH]        ;获取PEB_LDR_DATA结构的指针
                MOV        EAX,DWORD PTR [EAX+1CH] ;获取LDR_MODULE链表表首结点的inInitializeOrderModuleList成员的指针
                MOV        EAX,DWORD PTR [EAX]        ;LDR_MODULE链表第二个结点的inInitializeOrderModuleList成员的指针
                MOV        EAX,DWORD PTR [EAX+08H]        ;inInitializeOrderModuleList偏移8h便得到Kernel32.dll的模块基址
                MOV        EBP,EAX                ;        将Kernel32.dll模块基址地址放至kernel中
                MOV        EAX,DWORD PTR [EAX+3CH]        ;指向IMAGE_NT_HEADERS
                MOV        EAX,DWORD PTR [EBP+EAX+120]        ;指向导出表
                MOV        ECX,[EBP+EAX+24]        ;取导出表中导出函数名字的数目
                MOV        EBX,[EBP+EAX+32]          ;取导出表中名字表的地址
                ADD        EBX,EBP
                PUSH WORD  PTR 0X00                        ;构造GetProcAddress字符串
                PUSH DWORD PTR 0X73736572
                PUSH DWORD PTR 0X64644163
                PUSH DWORD PTR 0X6F725074
                PUSH WORD PTR 0X6547
                MOV  EDX,ESP
                PUSH ECX

               
F1:       
                MOV        EDI,EDX
                POP        ECX
                DEC        ECX
                TEST        ECX,ECX
                JZ        EXIT
                MOV        ESI,[EBX+ECX*4]               
                ADD        ESI,EBP
                PUSH        ECX
                MOV        ECX,15
                REPZ        CMPSB
                TEST        ECX,ECX
                JNZ        F1
       
                POP        ECX
                MOV        ESI,[EBP+EAX+36]        ;取得导出表中序号表的地址
                ADD        ESI,EBP
                MOVZX        ESI,WORD PTR[ESI+ECX*2]                ;取得进入函数地址表的序号
                MOV        EDI,[EBP+EAX+28]        ;取得函数地址表的地址
                ADD        EDI,EBP
                MOV        EDI,[EDI+ESI*4]                ;取得GetProcAddress函数的地址
                ADD        EDI,EBP                       
               
                PUSH WORD PTR 0X00                        ;构造LoadLibraryA字符串
                PUSH DWORD PTR 0X41797261
                PUSH DWORD PTR 0X7262694C
                PUSH DWORD PTR 0X64616F4C
                PUSH ESP
                PUSH        EBP
                CALL        EDI                        ;调用GetProcAddress取得LoadLibraryA函数的地址
                PUSH        WORD PTR 0X00                ;构造test符串,测试新增节后的EXE是否能正常加载test.dll
                PUSH        DWORD PTR 0X74736574
                PUSH        ESP
                CALL        EAX
EXIT:        ADD ESP,36                        ;平衡堆栈
                POPAD
}
shellend:
                char *pShell;
                int nShellLen;
__asm
{
                LEA EAX,shell
                MOV pShell,EAX;
                LEA EBX,shellend
                SUB EBX,EAX
                MOV nShellLen,EBX
}
       
        //写入SHELLCODE,
        for(i=0;i<nShellLen;i++)
                fputc(pShell[i],newfile);
        //SHELLCODE之后是跳转到原OEP的指令
        NewSection.VirtualAddress=SEChea.VirtualAddress+alig(SEChea.Misc.VirtualSize,SECTION_ALIG);
        BYTE jmp = 0xE9;
        OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5;
        fwrite(&jmp, sizeof(jmp), 1, newfile);
        fwrite(&OEP, sizeof(OEP), 1, newfile);
        //将最后增加的数据用0填充至按文件中对齐的大小
        for(i=0;i<alig(nShellLen,FILE_ALIG)-nShellLen-5;i++)
                fputc('\0',newfile);
        //新区块中的数据
        strcpy((char*)NewSection.Name,".llydd");
        NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData;
        NewSection.Misc.VirtualSize=nShellLen;
        NewSection.SizeOfRawData=alig(nShellLen,FILE_ALIG);
        NewSection.Characteristics=0xE0000020;//新区块可读可写可执行
        fseek(newfile,pNT+248+sizeof(IMAGE_SECTION_HEADER)*nOldSectionNo,0);

        //写入新的块表
        fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,newfile);

        int nNewImageSize=NThea.OptionalHeader.SizeOfImage+alig(nShellLen,SECTION_ALIG);
        int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+alig(nShellLen,FILE_ALIG);
        fseek(newfile,pNT,0);
        NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0;
        NThea.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0;
        NThea.OptionalHeader.SizeOfCode=nNewSizeofCode;
        NThea.OptionalHeader.SizeOfImage=nNewImageSize;
        NThea.FileHeader.NumberOfSections=nOldSectionNo+1;
        NThea.OptionalHeader.AddressOfEntryPoint=NewSection.VirtualAddress;
    //写入更新后的PE头结构
        fwrite(&NThea,sizeof(IMAGE_NT_HEADERS),1,newfile);
        printf("\t\tok.........!\n");

        fclose(newfile);
        fclose(rwFile);

        return 1;

}

/*不知为何只能生成debug版本,生成release时总提示
E:\vc6\TEST\add_section\add_section.cpp(210) : fatal error C1001: INTERNAL COMPILER ERROR
  (compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
    Please choose the Technical Support command on the Visual C++
    Help menu, or open the Technical Support help file for more information
Error executing cl.exe.
附:参考文献:《黑客防线》《程序员》,,
*/

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞7
打赏
分享
最新回复 (28)
雪    币: 380
活跃值: (101)
能力值: ( LV13,RANK:370 )
在线值:
发帖
回帖
粉丝
llydd 9 2006-12-17 00:10
2
0
声明:这算是对学习PE文件的一个学习总结,老虾若遇此帖就赶快跳过去吧,产生呕吐,板砖效应一概不负责
雪    币: 380
活跃值: (101)
能力值: ( LV13,RANK:370 )
在线值:
发帖
回帖
粉丝
llydd 9 2006-12-18 12:31
3
0
不知为何只能生成debug版本,生成release时总提示
E:\vc6\TEST\add_section\add_section.cpp(210) : fatal error C1001: INTERNAL COMPILER ERROR
  (compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
    Please choose the Technical Support command on the Visual C++
    Help menu, or open the Technical Support help file for more information
Error executing cl.exe.
命令行编译倒是没问题,等待高手支招。。。
雪    币: 214
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
colboy 2006-12-18 13:17
4
0
学习~~~~~~~~~~~~~~~
雪    币: 342
活跃值: (318)
能力值: ( LV12,RANK:740 )
在线值:
发帖
回帖
粉丝
aalloverred 18 2006-12-18 18:45
5
0
最初由 llydd 发布
不知为何只能生成debug版本,生成release时总提示
E:\vc6\TEST\add_section\add_section.cpp(210) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information
........


support.microsoft.com/kb/217164

BUG: You receive a "fatal error C1001" error message when you pass the return value of an intrinsic function as an argument to another function in Visual C++ 6.0
View products that this article applies to.
Article ID : 217164
Last Review : September 30, 2005
Revision : 3.0
This article was previously published under Q217164
On This Page

SYMPTOMS

RESOLUTION

STATUS

MORE INFORMATION

Steps to reproduce the behavior
SYMPTOMS
Bad code is generated when you pass the return value of an intrinsic function as an argument to a function that takes a reference to an integer while using Global Optimizations (/Og) and Enable Intrinsic Functions (/Oi). In some situations, a C1001 compiler error occurs:
fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
Back to the top

RESOLUTION
There are two workaround options: • Workaround 1: Disable intrinsic optimizations. Add /Oi- to your compiler switches after any other switches that start with /O.
• Workaround 2: Use #pragma function to prevent the use of individual intrinsic functions.

Back to the top

STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section. This bug was corrected in Visual Studio 6.0 Service Pack 3.

For more information about Visual Studio service packs, click the following article numbers to view the articles in the Microsoft Knowledge Base:
194022 (http://support.microsoft.com/kb/194022/) Visual Studio 6.0 service packs, what, where, why
194295 (http://support.microsoft.com/kb/194295/) How to tell that a Visual Studio service pack is installed
Back to the top

MORE INFORMATION
Steps to reproduce the behavior
Compile options: /Og /Oi or /O2
Workaround 1 compile options: /O2 /Oi- #include <stdio.h>
#include <math.h>

int f(const int &a, const int &b) {
return a * b;
}

// uncomment for workaround #2 to disable the abs intrinsic
// #pragma function(abs)

int main() {

int x = -45, y = 2;

// The result of abs(), an intrinsic, gets passed to
// a fn that takes arg of type reference to int
printf("Result of f() is %i\n", f(abs(x), y));

return 0;
}

// uncomment for workaround #2 to re-enable the abs intrinsic
// #pragma intrinsic(abs)

Back to the top


--------------------------------------------------------------------------------

APPLIES TO
• Microsoft Visual C++ 6.0 Professional Edition
• Microsoft Visual C++ 6.0 Standard Edition
• Microsoft Visual C++ 6.0 Enterprise Edition

Back to the top

Keywords: kbbug kbfix kbvc600fix kbcompiler kbvs600sp3fix KB217164

Back to the top


优化的问题,比较简单的解决方法,可以将工程设置中的release的“优化”设置为“缺省”(default).

个人觉得这不是什么问题,因为你也说命令行编译没问题。

好代码,谢谢共享,学习了。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
雨晨 2006-12-18 21:26
6
0
__asm
{
    LEA EAX,shell        ??? 这条指令!
    MOV pShell,EAX;
    LEA EBX,shellend
    SUB EBX,EAX
    MOV nShellLen,EBX
}
雪    币: 380
活跃值: (101)
能力值: ( LV13,RANK:370 )
在线值:
发帖
回帖
粉丝
llydd 9 2006-12-18 23:49
7
0
最初由 雨晨 发布
__asm
{
LEA EAX,shell ??? 这条指令!
MOV pShell,EAX;
LEA EBX,shellend
SUB EBX,EAX
MOV nShellLen,EBX
}

取得shellcode的起始地址,结束地址,然后求其长度
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhucheba 2006-12-19 09:20
8
0
好代码,谢谢共享
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
雨晨 2006-12-19 11:04
9
0
__asm
{
shell: PUSHAD
.....
}

shell 为函数内地址变量.
放到

shell:
__asm
{
PUSHAD
.....
}

或保存个变量转换一下
雪    币: 243
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bbzhu 2006-12-19 17:13
10
0
请问能不能翻译成DELPHI的,各位!
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Luis 2006-12-29 22:30
11
0
真的是好东西,学习下。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hzxhzx 2006-12-30 14:39
12
0
绝对是好东西啊....有人能翻成DELPHI的么?
雪    币: 2134
活跃值: (14)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
Aker 4 2007-5-28 00:54
13
0
EXIT:  ADD ESP,36      ;平衡堆栈
    POPAD

这里的36怎么来得,另外,好象不要平衡了吧,
雪    币: 380
活跃值: (101)
能力值: ( LV13,RANK:370 )
在线值:
发帖
回帖
粉丝
llydd 9 2007-5-28 15:39
14
0
由于我们自已构造了字符串,所以在调用完API函数后还要平衡堆栈
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinatme 2007-5-29 17:48
15
0
好东西,顶一下
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
monking 2007-7-5 03:49
16
0
向搂主学习!
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
robar 2007-7-5 11:42
17
0
好东东,顶一个
雪    币: 112
活跃值: (48)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
kenmark 2 2007-7-5 15:34
18
0
很好,现在的PE工具大多用麻烦的MFC做的用纯C做,用C的流读文件的看起来才最爽,MFC那个叫恶心啊,PE文件的处理还是用纯C最好,最多使用一些C++特性(如重载和类包装数据的概念)
雪    币: 372
活跃值: (31)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
vxin 10 2007-7-6 11:05
19
0
绝对是好东西啊....有人能翻成DELPHI的么?
雪    币: 209
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Jeller 2007-7-7 09:45
20
0
用哪种语言写的并不重要
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
不束之客 2007-7-8 14:46
21
0
希望 LZ能多加点注释 ..这样更方便理解.. . 谢谢
雪    币: 209
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Jeller 2007-7-15 01:29
22
0
Shellcode,很经典的
雪    币: 211
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
smallworm 2007-12-7 11:50
23
0
好贴字!好贴字 学习
雪    币: 205
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
强强 2007-12-9 00:28
24
0
有大侠知道这句话为什么不会覆盖原来的程序数据?不会出错吗?
//写入新的块表
  fwrite(&NewSection,sizeof(IMAGE_SECTION_HEADER),1,newfile);
据我所知,最后一个节表头后面跟的就是节的内容了,增加一个新的节表头,不会把第一个节的开始内容覆盖了吗?
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xxboy 2008-3-7 15:55
25
0
高手能说一下这个程序的执行过程吗?

运行后似乎没什么反映,

拜谢!
游客
登录 | 注册 方可回帖
返回