-
-
[旧帖] [原创] 用编程方式尝试增加区段 + C源码 0.00雪花
-
发表于: 2009-2-20 14:07 12147
-
【文章标题】: 用编程方式尝试增加区段+源码
【文章作者】: modi
【作者邮箱】: eerf@live.cn
【作者QQ号】: 16254479
【软件名称】: NULL
【下载地址】: 自己搜索下载
【编写语言】: C
【使用工具】: VC6,peid,winhex
【操作平台】: xp2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
第一次写破文,不知怎么下手,看到有朋友写了查找程序OEP的文章,顺着思路并参照<加密与解密二>中的PE讲解,头脑终于对DOS部首/PE文件头/块表,有了一点点头绪呵呵,彻喜中..趁热情高涨把笔记整理了一下,发出来..下文只是我浅陋的理解,可能表达的不是很好,没有系统学过呵呵.高手飘过,或者留下来拍砖哈..
我们知道用CreateFile函数打开一个文件后,返回的文件句柄就是指向DOS头那,就是‘MZ’这个地方..
以下结构解释部分摘自网络,DOS头结构是这样的:
typedef struct _IMAGE_DOS_HEADER
{
WORD e_magic; // ‘MZ’
WORD e_cblp; // 文件最后页的字节数
WORD e_cp; // 文件页数
WORD e_crlc; // 重定义元素个数
WORD e_cparhdr; // 头部尺寸,以段落为单位
WORD e_minalloc; // 所需的最小附加段
WORD e_maxalloc; // 所需的最大附加段
WORD e_ss; // 初始的SS值(相对偏移量)
WORD e_sp; // 初始的SP值
WORD e_csum; // 校验和
WORD e_ip; // 初始的IP值
WORD e_cs; // 初始的CS值(相对偏移量)
WORD e_lfarlc; // 重分配表文件地址
WORD e_ovno; // 覆盖号
WORD e_res[4]; // 保留字
WORD e_oemid; // OEM标识符(相对e_oeminfo)
WORD e_oeminfo; // OEM信息
WORD e_res2[10]; // 保留字
LONG e_lfanew; // 现在我们最关心的就是这个,偏移值是03Ch...
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
最后一个e_lfnew,占4字节的大小,PE文件头部就是由它保存在里面的。
既然知道PE文件头的偏移值,那么下一步就可以知道IMAGE_NT_HEADERS结构里面的信息了呵呵.
看一下结构:
typedef struct _IMAGE_NT_HEADERS
{
DWORD Signature;//PE文件头标志:"PE\0\0"。
IMAGE_FILE_HEADER FileHeader;//PE文件物理分布的信息,结构里面的NumberOfSections是我们后面用到的.
IMAGE_OPTIONAL_HEADER32 OptionalHeader;//PE文件逻辑分布的信息,
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
上面IMAGE_NT_HEADERS结构里还包含有两个结构如下:
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;//表示该程序要执行的环境及平台
WORD NumberOfSections;//块的数目,或者叫段的数目,是我们后面要用的.
DWORD TimeDateStamp;//文件建立的时间
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;//可选头的长度
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode; //可执行代码的长度
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint; //代码的入口RVA地址,程序就是从这里开始执行.
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase; //程序默认装入的基址RVA
DWORD SectionAlignment; //段加载后在内存中的对齐方式,这个后面要用到.
DWORD FileAlignment; //段在文件中的对齐方式,这个在后面要用到.
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage; //程序调入后占用内存总大小,这个在后面要用到.
DWORD SizeOfHeaders; //所有文件头长度之和.
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
在IMAGE_NT_HEADERS结构后面还有一个块表,包含每个块在映像中的信息.块的名称可以自定,譬如.test .rdata .data...等.每个块对应一个IMAGE_SECTION_HEADER结构.如下
前面知道了各部首的位置和大小,下面就可以实施:
1.通过e_lfanew值知道IMAGE_NT_HEADERS,就可以取出块数目/内存对齐值/文件对齐值/PE映像大小.
2.求出块表的总大小,块数 x sizeof(IMAGE_SECTION_HEADER)
3.最后块表的偏移=e_lfanew值 + sizeof(IMAGE_NT_HEADERS) + 块表的总大小
4.创建一个新块头并填充,然后写入最后块表偏移处
5,修正原来程序块数目,和内存映像大小,并填充好数据.
下面是自己写的烂代码,勉强编译通过..汗.
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
{
DialogBox(hInstance, (LPCTSTR)IDD_DIALOG1, NULL, (DLGPROC)DlgProc);
return 0;
}
LRESULT CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
char buff[MAX_PATH]={0};
OPENFILENAME openfilename;
HANDLE hFile;
DWORD dwPEHeader_OffSet=0,dwPEHeader_OffSet_bak=0;
DWORD dwFileRead=0;
IMAGE_NT_HEADERS PEHeader;
DWORD dwSection_offset=0;
IMAGE_SECTION_HEADER NewSectionHeader;
char NewSectionName[8]=".yang";
DWORD LastSection_Ro=0;
DWORD LastSection_Rs=0;
DWORD LastSizeOfImage=0;
DWORD VirtualAdd=0;
switch (message)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
ZeroMemory(&openfilename,sizeof(OPENFILENAME));
openfilename.lStructSize=sizeof(OPENFILENAME);
openfilename.hwndOwner=hDlg;
openfilename.lpstrFile=buff;
openfilename.nMaxFile=MAX_PATH;
openfilename.lpstrFilter="可执行文件(*.exe)\0*.exe\0";
openfilename.Flags=OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
GetOpenFileName(&openfilename);
hFile=CreateFile(buff, GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ( hFile== INVALID_HANDLE_VALUE)
{
MessageBox(hDlg,"打开文件失败!","错误",NULL);
return FALSE;
}
SetFilePointer(hFile, 0x3C, 0, FILE_BEGIN);//设置指针在PE头入口
ReadFile(hFile, &dwPEHeader_OffSet, 0x4, &dwFileRead, NULL);
dwPEHeader_OffSet_bak=dwPEHeader_OffSet;//备份PE偏移地址
SetFilePointer(hFile, dwPEHeader_OffSet, 0, FILE_BEGIN);//指针在PE头
ReadFile( hFile, &PEHeader, sizeof(IMAGE_NT_HEADERS), &dwFileRead, NULL);//读出PE头
dwSection_offset=0x4+sizeof(IMAGE_FILE_HEADER)+sizeof(IMAGE_OPTIONAL_HEADER)
+PEHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
+dwPEHeader_OffSet;//最后区块的偏移地址
PEHeader.FileHeader.NumberOfSections+=1;//块数增加1
SetFilePointer(hFile, dwPEHeader_OffSet+0x6, 0, FILE_BEGIN);//指针到块数
WriteFile(hFile,&PEHeader.FileHeader.NumberOfSections,0x2,&dwFileRead, NULL);//写入新块数目
NewSectionHeader.Name[8]=(BYTE)"乱码?";//新块名
NewSectionHeader.Misc.VirtualSize=0x500; //新块的大小
NewSectionHeader.VirtualAddress=PEHeader.OptionalHeader.SizeOfImage;//Voffset
if(NewSectionHeader.Misc.VirtualSize > PEHeader.OptionalHeader.FileAlignment )
NewSectionHeader.SizeOfRawData=(NewSectionHeader.Misc.VirtualSize / PEHeader.OptionalHeader.FileAlignment+1)*
PEHeader.OptionalHeader.FileAlignment;
else
NewSectionHeader.SizeOfRawData=PEHeader.OptionalHeader.FileAlignment;
SetFilePointer(hFile,dwSection_offset-0x14,0, FILE_BEGIN);//设置到最后一块的Roffset
ReadFile(hFile,&LastSection_Ro,0x4,&dwFileRead, NULL);//读取最后一块的Roffset
SetFilePointer(hFile,dwSection_offset-0x18,0, FILE_BEGIN);//设置到最后一块的Rsize
ReadFile(hFile,&LastSection_Rs,0x4,&dwFileRead, NULL);//读取最后一块的Rsize
NewSectionHeader.PointerToRawData=LastSection_Ro+LastSection_Rs;//新块文件偏移
NewSectionHeader.PointerToRelocations=0;
NewSectionHeader.PointerToLinenumbers=0;
NewSectionHeader.NumberOfRelocations=0;
NewSectionHeader.NumberOfLinenumbers=0;
NewSectionHeader.Characteristics=0xE0000020;//可读可写可执行
SetFilePointer(hFile,dwSection_offset,0, FILE_BEGIN);//设置回最后块
WriteFile(hFile,&NewSectionHeader,sizeof(IMAGE_SECTION_HEADER),&dwFileRead,NULL);//写入新块
//以下计算出sizeofimage大小
if(NewSectionHeader.Misc.VirtualSize > PEHeader.OptionalHeader.SectionAlignment )
PEHeader.OptionalHeader.SizeOfImage+=((NewSectionHeader.Misc.VirtualSize / PEHeader.OptionalHeader.SectionAlignment+1)*
PEHeader.OptionalHeader.SectionAlignment);
else
PEHeader.OptionalHeader.SizeOfImage+=PEHeader.OptionalHeader.SectionAlignment;
SetFilePointer(hFile,dwPEHeader_OffSet_bak+0x50,0, FILE_BEGIN);
WriteFile(hFile,&PEHeader.OptionalHeader.SizeOfImage,0x4,&dwFileRead,NULL);//写入新的sizeofimage
SetFilePointer(hFile,NewSectionHeader.PointerToRawData,0,FILE_BEGIN);//指针到块最后Roffset准备写入字节
VirtualAdd=(DWORD)VirtualAlloc(NULL,NewSectionHeader.SizeOfRawData,MEM_COMMIT,PAGE_READWRITE);//写入数量怎么变回十进制?
if(VirtualAdd ==NULL)
{
MessageBox(hDlg,"申请内存失败!","",NULL);//(BYTE)NewSectionHeader.SizeOfRawData
CloseHandle(hFile);
return FALSE;
}
WriteFile(hFile,&VirtualAdd,NewSectionHeader.SizeOfRawData,&dwFileRead,NULL);
if(VirtualFree((LPVOID)VirtualAdd,NewSectionHeader.SizeOfRawData,MEM_DECOMMIT)==0)
{
MessageBox(hDlg,"内存未释放!","错误",NULL);
CloseHandle(hFile);
return FALSE;
}
MessageBox(hDlg,"添加成功!","提示",NULL);
CloseHandle(hFile);
return TRUE;
case ID_EXIT:
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
终于写完了,第一次写破文,写到这里,眼睛都痛了..
添加成功,有时运行不起可能是有壳,文件有校验,绑定输入表没有清除等...
add.rar
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年02月20日 14:01:48
本代码的着色效果由xTiNt自动完成
下载xTiNt
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创] 用编程方式尝试增加区段 + C源码 12148
- [调查]有没有广东茂名的朋友? 6394
- [求助]WriteProcessMemory函数参数定义问题 7214
- <求助>瑞星是如何检测到我的补丁呢? 4813
- [求助]OD使用小问题.... 3498