三月份写的代码,拉出来,重新整理一下。
第一次来看雪发帖,也是第一次发技术贴,求顶求支持,求精华
pe结构为:
这里我只关注导入导出表,即图的输入输出表
先说段开场白吧,pe文件在磁盘映射或者加载到内存的时候,dos头,PE头不会有任何修改,但是在节表,也就section这块会有一定的修正,其实这个问题最开始给我很大的困惑。
具体几个步骤,详细步骤在代码里有
1.创建文件
2.映射文件,保留一个基地址
3.dos头=基地住
4.pe头=dos头+pe文件的偏移
5.导出表的偏移RVA=p_NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
6.导出表的地址=RVA+基地址,此时的导出表应该为第一个导出表
7.此时我们可以取得导出表的所有的数据,本程序取得其中的函数名,函数地址,以及导出函数的总数---------此处注意,因为这些数据都是存放在section里面的,在导出表中只是存的是一个指针,然后根据第一段的开场白,这个地址不准了,此时,要做一个修正了。
8.我们找到section头的位置,pe头+pe的大小
9.把section里面的磁盘的偏移-内存中的偏移+导出表原来指向RVA,这样就找到了导出表函数的位置了-----------这句再详解一下,按照我的测试条件下,磁盘上的pe文件较内存上的小些,即可以把磁盘上的看做为压缩文件,而导出表的RVA也是压缩的RVA,要转化成内存的RVA,实际内存里的RVA =磁盘RVA+磁盘section偏移-内存section偏移
10找到导出表的函数存储的地址就可以找到所要的函数名,函数个数,以及函数地址
同理找到导出表。】
代码:【附件里也有】
#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "advapi32.lib")
//
//提权
//
bool enableDebugPriv()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
return false;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {
CloseHandle(hToken);
return false;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
CloseHandle(hToken);
return false;
}
return true;
}
//
//修正RVA
//
DWORD update_RVA(PIMAGE_NT_HEADERS pNTHeader, DWORD dwRVA){
PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS));
for(int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
{
if(dwRVA >= pSection[i].VirtualAddress && dwRVA < (pSection[i].VirtualAddress + pSection[i].SizeOfRawData))
{
return pSection[i].PointerToRawData + (dwRVA - pSection[i].VirtualAddress);
}
}
return 0;
}
//
//打印导出表
//
int show_Export(char *file){
//创建文件
HANDLE h_File = CreateFileA(file, GENERIC_ALL, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if (h_File==NULL){
printf("创建失败\n");
if (INVALID_HANDLE_VALUE != h_File){
CloseHandle(h_File);
}
return 1;
}
//映射文件到内存
HANDLE h_Mapping = CreateFileMapping(h_File, NULL, PAGE_READWRITE, 0, 0, NULL);
if (h_Mapping==NULL){
printf("文件映射失败\n");
if(NULL != h_Mapping){
CloseHandle(h_Mapping);
}
CloseHandle(h_File);
return 1;
}
//基地址
PVOID BaseAdress= MapViewOfFile(h_Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if(BaseAdress==NULL){
printf("取基地址失败\n");
if(NULL != h_File){
UnmapViewOfFile(h_File);
}
CloseHandle(h_Mapping);
CloseHandle(h_File);
return 1;
}
//DOS头
PIMAGE_DOS_HEADER p_DosHeader = (PIMAGE_DOS_HEADER)BaseAdress;
//PE头
PIMAGE_NT_HEADERS p_NTHeader = (PIMAGE_NT_HEADERS)((DWORD)BaseAdress + p_DosHeader->e_lfanew);
//导出表的RVA
DWORD dwExp= p_NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if(dwExp==0){
printf("没有导出表\n");
UnmapViewOfFile(h_File);
CloseHandle(h_Mapping);
CloseHandle(h_File);
return 1;
}
//内存里导出表的地址,此处需要修正
PIMAGE_EXPORT_DIRECTORY p_Export = (PIMAGE_EXPORT_DIRECTORY)((DWORD)BaseAdress + update_RVA(p_NTHeader,dwExp));
//
//第一个函数名称的地址
DWORD* p_NamesAddress = (DWORD*)((DWORD)BaseAdress +update_RVA(p_NTHeader,p_Export->AddressOfNames));
//
//指向函数导出表地址的RVA+基地址
DWORD* p_FunctionAddress = (DWORD*)((DWORD)BaseAdress + update_RVA(p_NTHeader,p_Export->AddressOfFunctions));
//指向函数名序号表的RVA+基地址
WORD* p_Ordinals = (WORD*)((DWORD)BaseAdress +update_RVA(p_NTHeader,p_Export->AddressOfNameOrdinals));
int num=p_Export->NumberOfNames;
for(int i = 0;i<num; i++)
{
DWORD dwFunctionAddress = p_FunctionAddress[p_Ordinals[i]];
DWORD p_FunName = (DWORD)BaseAdress +update_RVA(p_NTHeader,p_NamesAddress[i]);
//pExport->Base导出函数的起始序号
//
printf("[导出表序号]: %-4d [函数名]: %-30s [地址]: 0x%08X\n", p_Export->Base + i, p_FunName, dwFunctionAddress);
}
UnmapViewOfFile(h_File);
CloseHandle(h_Mapping);
CloseHandle(h_File);
return 0;
}
//
//打印导入表
//
int show_Import(char *file){
//创建文件
HANDLE h_File = CreateFileA(file, GENERIC_ALL, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if (h_File==NULL){
printf("创建文件失败\n");
if (INVALID_HANDLE_VALUE != h_File){
CloseHandle(h_File);
}
return 1;
}
//映射文件到内存
HANDLE h_Mapping = CreateFileMapping(h_File, NULL, PAGE_READWRITE, 0, 0, NULL);
if (h_Mapping==NULL){
printf("文件映射失败\n");
if(NULL != h_Mapping){
CloseHandle(h_Mapping);
}
CloseHandle(h_File);
return 1;
}
//基地址
PVOID BaseAdress= MapViewOfFile(h_Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (BaseAdress==NULL){
printf("获取基地址失败\n");
if(NULL != h_File){
UnmapViewOfFile(h_File);
}
CloseHandle(h_Mapping);
CloseHandle(h_File);
return 1;
}
//DOS头
PIMAGE_DOS_HEADER p_DosHeader = (PIMAGE_DOS_HEADER)BaseAdress;
//PE头
PIMAGE_NT_HEADERS p_NTHeader = (PIMAGE_NT_HEADERS)((DWORD)BaseAdress + p_DosHeader->e_lfanew);
//导出表的RVA
DWORD dwImp= p_NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if (dwImp==0){
printf("没有导入表\n");
UnmapViewOfFile(h_File);
CloseHandle(h_Mapping);
CloseHandle(h_File);
return 1;
}
//内存里导出表的地址,此处需要修正
PIMAGE_IMPORT_DESCRIPTOR p_Import = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)BaseAdress + update_RVA(p_NTHeader,dwImp));
DWORD* p_NamesAddress = (DWORD*)((DWORD)BaseAdress +update_RVA(p_NTHeader,p_Import->OriginalFirstThunk));
int i=0;
while(1)
{
//俩个位子的函数序列号,名字要往后移俩位
DWORD p_FunName = (DWORD)BaseAdress +update_RVA(p_NTHeader,p_NamesAddress[i])+2;
printf("[导入函数名:] %-30s \n",p_FunName);
i++;
if(p_NamesAddress[i]==0){
break;
}
}
UnmapViewOfFile(h_File);
CloseHandle(h_Mapping);
CloseHandle(h_File);
return 0;
}
int main()
{
bool power=enableDebugPriv();//提权
if(power==false){
printf("提权失败\n");
return 1;
}
while(power==true){
printf("请输入文件路径以及文件名:\n");
char file[30];
scanf("%s",file);
printf("导出表为:\n");
show_Export(file);
printf("导入表为:\n");
show_Import(file);
}
return 0;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)