- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试为任意进程访问导入地址表
中延迟加载的函数地址。
我的假设是这样的:
首先,我需要查看它在图像中相对于基地址的位置:
DWORD_PTR dwFuncOffset = get_IAT_entry_offset_for_imported_function(
L"path-to\\TargetProc.exe", "WTSAPI32.dll", "WTSOpenServerW");
wprintf(L"Offset is 0x%p\n", dwFuncOffset);
这是 PE header 中查找的一些简化版本。我删除了大部分错误检查以使其可读:
#include <delayimp.h>
#include <Dbghelp.h>
#pragma comment(lib, "Dbghelp.lib")
PIMAGE_SECTION_HEADER getEnclosingSectionHeader(DWORD_PTR rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
for (WORD i = 0 ; i < pNTHeader->FileHeader.NumberOfSections; i++, section++)
{
// Is the RVA within this section?
if((rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
{
return section;
}
}
return 0;
}
LPVOID GetPtrFromRVA(DWORD_PTR rva, PIMAGE_NT_HEADERS pNTHeader, DWORD_PTR imageBase)
{
PIMAGE_SECTION_HEADER pSectionHdr = getEnclosingSectionHeader(rva, pNTHeader);
if (!pSectionHdr)
return 0;
INT_PTR delta = (INT_PTR)(pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData);
return (PVOID)(imageBase + rva - delta);
}
DWORD_PTR get_IAT_entry_offset_for_imported_function(LPCTSTR pImageFilePath, LPCSTR pImportDllName, LPCSTR pImportFuncName)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hOpenFileMapping = NULL;
const BYTE* lpBaseAddress = NULL;
__try
{
hFile = CreateFile(pImageFilePath,
GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
hOpenFileMapping = ::CreateFileMapping(hFile,
NULL, PAGE_READONLY, 0, 0, NULL);
lpBaseAddress = (const BYTE*)::MapViewOfFile(hOpenFileMapping,
FILE_MAP_READ, 0, 0, 0);
if(!lpBaseAddress)
return 0;
PIMAGE_NT_HEADERS pNtHeader = ::ImageNtHeader((PVOID)lpBaseAddress);
_ASSERT(pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC); //32-bit only here
IMAGE_OPTIONAL_HEADER32* pIOH32 = &reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeader)->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDirectories = pDataDirectories = pIOH32->DataDirectory;
IMAGE_DATA_DIRECTORY* pDLoadTbl = &pDataDirectories[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
ImgDelayDescr *pImportDescriptor = (ImgDelayDescr*)GetPtrFromRVA(
pDLoadTbl->VirtualAddress, pNtHeader, (DWORD_PTR)lpBaseAddress);
//Go through all DLLs
for(; pImportDescriptor->rvaIAT; pImportDescriptor++)
{
//Get DLL name
LPCSTR pStrDllName = (LPCSTR)GetPtrFromRVA(pImportDescriptor->rvaDLLName,
pNtHeader, (DWORD_PTR)lpBaseAddress);
//Look for specific import dll
if(lstrcmpiA(pStrDllName, pImportDllName) != 0)
continue;
IMAGE_THUNK_DATA32 *pITD_IAT = (IMAGE_THUNK_DATA32*)
GetPtrFromRVA(pImportDescriptor->rvaIAT, pNtHeader, (DWORD_PTR)lpBaseAddress);
IMAGE_THUNK_DATA32 *pITD_INT = (IMAGE_THUNK_DATA32*)
GetPtrFromRVA(pImportDescriptor->rvaINT, pNtHeader, (DWORD_PTR)lpBaseAddress);
//Go through all imported functions from this DLL
for(; pITD_INT->u1.AddressOfData != 0; pITD_IAT++, pITD_INT++)
{
if(IMAGE_SNAP_BY_ORDINAL32(pITD_INT->u1.Ordinal))
continue;
IMAGE_IMPORT_BY_NAME* pIIBY = (IMAGE_IMPORT_BY_NAME*)
GetPtrFromRVA(pITD_INT->u1.AddressOfData, pNtHeader, (DWORD_PTR)lpBaseAddress);
if(!pIIBY)
continue;
//Pick only specific imported function
if(lstrcmpiA((LPCSTR)pIIBY->Name, pImportFuncName) != 0)
continue;
//Get this function's offset in IAT relative to base address
return (DWORD_PTR)pITD_IAT - (DWORD_PTR)lpBaseAddress;
}
}
}
__finally
{
::UnmapViewOfFile(lpBaseAddress);
::CloseHandle(hOpenFileMapping);
::CloseHandle(hFile);
}
return 0; //failed
}
然后我将 TargetProc.exe
构建为一个简单的控制台项目,并将 WTSAPI32.dll
设置为延迟加载:
TargetProc.exe
只有这段代码:
#include "stdafx.h"
#include <Windows.h>
#include <Wtsapi32.h>
#pragma comment(lib, "Wtsapi32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
//Get base address for this image
void* pBaseAddr = (void*)::GetModuleHandle(NULL);
::WTSOpenServerW(NULL); //Set up for delayed loading
return 0;
}
然后我运行我的第一个项目,该项目为我提供了 WTSOpenServerW
函数的 IAT 条目相对于 TargetProc.exe
的偏移量是:
Offset is 0x00007670
我可以用调试器验证:
那么第二阶段就是检查了。
因此,如果我在 Visual Studio 中运行我的 TargetProc.exe
,我可以首先获取它的基地址(恰好是 0x890000
):
然后我可以进入 WTSOpenServerW
函数来查看其 IAT 条目的位置:
跳过那个跳转,它只在调试器构建中添加到这里。
这是它实际从 jmp
指令的 IAT 条目中读取 WTSOpenServerW
函数地址的地方:
我在地址 0x008AB070
处获取它的 IAT 条目,它恰好位于基地址的 0x1B070
字节偏移处(即 0x008AB070
- 0x890000
= 0x1B070
),而不是我上面计算的预期 0x7670
。
那么我在计算中做错了什么?
附言。 PE头结构reference 1和 reference 2 .
最佳答案
我想我成功了。我不确定是否有更好的方法来优化 GetPtrFromRVA
函数调用,但对于较大的 PE 文件,这可能会占用一些 CPU 时钟。
所以对我最初的问题的简短回答是肯定的,当文件被映射执行时,PE 文件部分可以根据它们在 PE 文件中的位置在内存中重新定位。
这里有两种读取导入地址表的方法(在我的例子中是延迟加载的 DLL):从图像文件和当前进程内存。 (还有第三种方法可以通过读取其虚拟内存从另一个正在运行的进程中获取它。This guy shows how。在这种情况下,我的方法是将我的 DLL 注入(inject)到进程中并使用 parsePEheader_DelayLoad_FromMem()
方法。)
wprintf(L"Memory:----------------------\n");
parsePEheader_DelayLoad_FromMem((void*)::GetModuleHandle(NULL), TRUE);
wprintf(L"File:----------------------\n");
WCHAR buff[MAX_PATH];
::GetModuleFileName(NULL, buff, _countof(buff));
parsePEheader_DelayLoad_FromFile(buff);
然后是代码本身:(请注意,还有一种旧式 PE header 格式,由 Visual Studio 6.0 使用,我也必须考虑到这一点。)
BOOL parsePEheader_DelayLoad_FromFile(LPCTSTR pImageFilePath)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hOpenFileMapping = NULL;
void* lpBaseAddress = NULL;
__try
{
hFile = CreateFile(pImageFilePath,
GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
hOpenFileMapping = ::CreateFileMapping(hFile,
NULL, PAGE_READONLY, 0, 0, NULL);
lpBaseAddress = (void*)::MapViewOfFile(hOpenFileMapping,
FILE_MAP_READ, 0, 0, 0);
if(!lpBaseAddress)
return FALSE;
return parsePEheader_DelayLoad_FromMem(lpBaseAddress, FALSE);
}
__finally
{
::UnmapViewOfFile(lpBaseAddress);
::CloseHandle(hOpenFileMapping);
::CloseHandle(hFile);
}
return FALSE;
}
BOOL parsePEheader_DelayLoad_FromMem(void* lpBaseAddress, BOOL bImage)
{
__try
{
PIMAGE_SECTION_HEADER pDummy;
ULONG uiDummy;
ImgDelayDescr *pImportDescriptor = (ImgDelayDescr*)ImageDirectoryEntryToDataEx(
lpBaseAddress, bImage, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, &uiDummy, &pDummy);
if(pImportDescriptor)
{
const char* base = (char*)lpBaseAddress;
IMAGE_NT_HEADERS* pNtHeader =
(IMAGE_NT_HEADERS*)((BYTE*)lpBaseAddress +
((IMAGE_DOS_HEADER*)lpBaseAddress)->e_lfanew);
DWORD_PTR uiPreferredBase = pNtHeader->OptionalHeader.ImageBase;
//Go thru all DLLs
while(pImportDescriptor->rvaIAT)
{
PIMAGE_THUNK_DATA nameTable = 0;
PIMAGE_THUNK_DATA funcTable = 0;
const char* dllName;
BOOL bOldStyle;
if(pImportDescriptor->grAttrs & 1)
{
bOldStyle = FALSE;
if(!bImage)
{
nameTable = (PIMAGE_THUNK_DATA)
GetPtrFromRVA(pImportDescriptor->rvaINT, pNtHeader, (DWORD_PTR)lpBaseAddress);
funcTable = (PIMAGE_THUNK_DATA)
GetPtrFromRVA(pImportDescriptor->rvaIAT, pNtHeader, (DWORD_PTR)lpBaseAddress);
dllName = (const char*)
GetPtrFromRVA(pImportDescriptor->rvaDLLName, pNtHeader, (DWORD_PTR)lpBaseAddress);
}
else
{
nameTable = (PIMAGE_THUNK_DATA)(base + pImportDescriptor->rvaINT);
funcTable = (PIMAGE_THUNK_DATA)(base + pImportDescriptor->rvaIAT);
dllName = base + pImportDescriptor->rvaDLLName;
}
}
else
{
//Old style PE file, compiled with VC++ 6.0
//Cannot be 64-bit
_ASSERT(sizeof(DWORD_PTR) == sizeof(DWORD));
bOldStyle = TRUE;
if(!bImage)
{
nameTable = (PIMAGE_THUNK_DATA)
GetPtrFromRVA((DWORD_PTR)pImportDescriptor->rvaINT - uiPreferredBase, pNtHeader, (DWORD_PTR)lpBaseAddress);
funcTable = (PIMAGE_THUNK_DATA)
GetPtrFromRVA((DWORD_PTR)pImportDescriptor->rvaIAT - uiPreferredBase, pNtHeader, (DWORD_PTR)lpBaseAddress);
dllName = (LPCSTR)((DWORD_PTR)lpBaseAddress + (DWORD_PTR)pImportDescriptor->rvaDLLName - uiPreferredBase);
}
else
{
nameTable = (PIMAGE_THUNK_DATA)(base + pImportDescriptor->rvaINT - uiPreferredBase);
funcTable = (PIMAGE_THUNK_DATA)(base + pImportDescriptor->rvaIAT - uiPreferredBase);
dllName = base + pImportDescriptor->rvaDLLName - uiPreferredBase;
}
}
printf("Delay Loaded DLL: %s\n", dllName);
while(nameTable->u1.AddressOfData)
{
// check whether this is imported by ordinal only
if(nameTable->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
WORD ordinal = static_cast<WORD>(nameTable->u1.Ordinal & (~IMAGE_ORDINAL_FLAG));
printf("ordinal: %u", ordinal);
}
else
{
PIMAGE_IMPORT_BY_NAME funcNameStruct;
if(!bImage)
{
if(!bOldStyle)
{
funcNameStruct = (PIMAGE_IMPORT_BY_NAME)
GetPtrFromRVA((DWORD_PTR)nameTable->u1.AddressOfData, pNtHeader, (DWORD_PTR)lpBaseAddress);
}
else
{
funcNameStruct = (PIMAGE_IMPORT_BY_NAME)
GetPtrFromRVA((DWORD_PTR)nameTable->u1.AddressOfData - uiPreferredBase, pNtHeader, (DWORD_PTR)lpBaseAddress);
}
}
else
{
if(!bOldStyle)
{
funcNameStruct = (PIMAGE_IMPORT_BY_NAME)
(base + (DWORD_PTR)nameTable->u1.AddressOfData);
}
else
{
funcNameStruct = (PIMAGE_IMPORT_BY_NAME)
(base + (DWORD_PTR)nameTable->u1.AddressOfData - uiPreferredBase);
}
}
char* pFuncName = (char*)funcNameStruct->Name;
printf("func: %s", pFuncName);
}
printf("\tAddr: [0x%p]=0x%p\n",
funcTable, *(DWORD_PTR*)funcTable);
nameTable++;
funcTable++;
}
pImportDescriptor++;
}
}
else
{
wprintf(L"There's no Delay loaded DLLs\n");
}
return TRUE;
}
__except(1)
{
wprintf(L"\nException! Bad address, not a PE file, or something goofed up...\n");
return FALSE;
}
}
最后,如果您不想链接到 Dbghelp.lib
只是为了使用它的几个函数,这些是它们的 C 实现:
PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, PULONG size, PIMAGE_SECTION_HEADER *section )
{
const IMAGE_NT_HEADERS *nt;
DWORD addr;
*size = 0;
if (section)
*section = NULL;
if (!(nt = RtlImageNtHeader( (HMODULE)base )))
return NULL;
if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes)
return NULL;
if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress))
return NULL;
*size = nt->OptionalHeader.DataDirectory[dir].Size;
if (image || addr < nt->OptionalHeader.SizeOfHeaders)
return (char *)base + addr;
return RtlImageRvaToVa( nt, (HMODULE)base, addr, section );
}
PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module, DWORD rva, IMAGE_SECTION_HEADER **section )
{
IMAGE_SECTION_HEADER *sec;
if (section && *section)
{
sec = *section;
if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
goto lbl_use_it;
}
if (!(sec = RtlImageRvaToSection( nt, module, rva )))
return NULL;
lbl_use_it:
if (section)
*section = sec;
return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
}
PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt, HMODULE module, DWORD rva )
{
int i;
const IMAGE_SECTION_HEADER *sec;
sec = (const IMAGE_SECTION_HEADER*)(
(const char*)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
{
if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
return (PIMAGE_SECTION_HEADER)sec;
}
return NULL;
}
PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
{
IMAGE_NT_HEADERS *ret;
__try
{
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
ret = NULL;
if (dos->e_magic == IMAGE_DOS_SIGNATURE)
{
ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
if (ret->Signature != IMAGE_NT_SIGNATURE)
ret = NULL;
}
}
__except(1)
{
return NULL;
}
return ret;
}
关于c++ - 加载图像时,PE文件部分是否可以相对于基地址在内存中移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48000139/
当我编译我的 ionic 4 应用程序时,我得到这个错误:不开始。但是,如果我更改代码中的某些内容并再次编译,代码将成功编译。我查了一下它可能与路径(绝对/相对)有关。但在这些问题中,解决方案是使用相
现在我发现当我打开终端时,它总是显示这些消息: bash: /usr/local/texlive/2012/texmf/doc/man:: No such file or directory bash
我有一些具有不同 url 前缀的嵌套模块。现在我想在一个模块中导航而不指定前缀(在我的模块中,我不想知道在哪个前缀下可以访问该模块)。 这些是我的 app.module 的路线: const APP_
我想在java中进行日期范围搜索假设我想搜索从2019年10月22日到当前日期。但问题是在两周的 block 大小中进行日期范围搜索(考虑到这可能会有所不同,但以周为单位),例如这里开始日期将为 20
我正在尝试实现移动到单击鼠标的点。 但是我遇到了 X 轴镜像行为的问题。当我点击顶部 -> 它移动到底部,当我点击底部 -> 它移动到顶部。 这里是原始位置的例子 我点击了屏幕上有红十字的位置。 但它
尝试使用以下方法让对象跟随光标: int mx =(int) MouseInfo.getPointerInfo().getLocation().getX()-50; Player.setX(mx);
我有 4 个 JButton 设置在彼此下方。我希望当用户水平调整框架大小时它们左右移动。 例如:帧大小:400,400 按钮位置:300,200 现在我将框架大小调整为:600,400 Button
我想要做的是将一个元素(我用作背景的彩色 UIView)定位到我的 Storyboard 中,以便它从 ImageField 的中间开始。并填充所有内容,直到屏幕底部。我正在使用 xcode7 和 s
我正在编写一些 C++ 代码,它主要为共享它的其他两个项目提供一个类,但也包括一个小程序,以便在需要时可以从命令行使用它。该类必须加载一些资源,这些资源被写入资源文件夹中的多个文件。这些文件的路径当然
我能以某种方式随时获得相对于帧初始引用的加速度矢量吗? (我的意思是:xArbitraryZVertical 模式下的帧引用,我第一次得到 Core Motion 数据)我试图做什么:每次我得到 CM
saved 我希望 div#one 在父 div 的左边缘和提交按钮的左边缘之间的空间居中。 最佳答案 还有几种方法: saved 很难说 saved 文本没有居中在容器 d
所以我在页面上有一个带有背景图像的对象,在 mousemove 上它移动了相对于鼠标的背景位置。但我遇到的唯一问题是在鼠标进入对象时将背景图像动画化到鼠标的当前位置。 我能够将背景位置动画化回其原始位
我的一个网站中有一个图像缩放属性。我想相对于 div 的中心缩放图像。 缩放功能如下。 function zoom(zm) { img=document.getElementById("pic"
我正在尝试调整水平导航栏左侧的导航栏 Logo 的大小,然后让其余导航栏元素占据相同的垂直空间并在空间中垂直居中。导航栏元素目前不使用完整的垂直空间。我尝试过的每个尺寸属性都产生了另一个问题。感谢所有
我有一些 h2 文本当前在移动 View 中左对齐,位于居中的 div 上方。我怎样才能将它对齐到移动 View 中相对于 div 的左对齐(应用下面的 CSS 中提供的媒体查询)? CodePen
我想让文本元素(在本例中为 h2 副标题)居中,方法是让它忽略左侧的 float 图像。我更喜欢 h2 副标题与 h1 标题垂直居中对齐。有没有什么办法可以单独使用 CSS 来做到这一点? 这是一个示
您好! 我在这个网站上工作,但我一直遇到同样的问题。当我把边距放在百分比而不是像素时,它似乎是从包装器或页面中获取百分比。可能是一些愚蠢的错误,但我并没有真正使用过百分比。无论如何,我所说的类是“ L
我很好奇这是怎么做到的,我做了类似的东西,例如 Home About Search bar Container
我希望我的 firstLabel 位于同一行文本字段的右侧。 //css input[type="text"]{ display:block; margin-botto
我正在尝试绘制多边形,并希望能够单击我的框架以获取鼠标坐标,以便更快地将心理图像转换为 x/y 值。 我在用 System.out.println("("+ MouseInfo.getPointerI
我是一名优秀的程序员,十分优秀!