Names;
// 遍历节结构进行地址运算
pSectionHeader = pOldSectionHeader;
for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
{
if (pSectionHeader->VirtualAddress <= FileOffset && FileOffset <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
{
FileOffset = FileOffset - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
}
}
AddressOfNames = (PULONG)((ULONGLONG)BaseAddress + FileOffset);
// 分析导出表
ULONG uOffset;
LPSTR FunName;
ULONG uAddressOfNames;
ULONG TargetOff = 0;
for (ULONG uIndex = 0; uIndex < pExportDirectory->NumberOfNames; uIndex++, AddressOfNames++, AddressOfNameOrdinals++)
{
uAddressOfNames = *AddressOfNames;
pSectionHeader = pOldSectionHeader;
for (UINT16 Index = 0; Index < pNtHeaders->FileHeader.NumberOfSections; Index++, pSectionHeader++)
{
if (pSectionHeader->VirtualAddress <= uAddressOfNames && uAddressOfNames <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
{
uOffset = uAddressOfNames - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
}
}
FunName = (LPSTR)((ULONGLONG)BaseAddress + uOffset);
// 如果找到则返回RVA
if (!_stricmp((const char *)FunctionName, FunName))
{
// 等于1则返回RVA
if (Flag == 1)
{
TargetOff = (ULONG)AddressOfFunctions[*AddressOfNameOrdinals];
// DbgPrint("索引 [ %p ] 函数名 [ %s ] 相对RVA [ %p ] \n", *AddressOfNameOrdinals, FunName, TargetOff);
return TargetOff;
}
// 返回索引
else if (Flag == 0)
{
return *AddressOfNameOrdinals;
}
}
}
// 结束后释放内存
ExFreePoolWithTag(BaseAddress, (ULONG)"LyShark");
return 0;
}
调用该函数很容易,传入模块路径以及该模块内的函数名,解析出RVA地址或Index下标。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
// 函数分别传入 [模块路径,函数名,标志=1] 返回该导出函数的RVA
ULONG64 get_rva = GetRvaFromModuleName(L"\\SystemRoot\\system32\\ntoskrnl.exe", "NtReadFile", 1);
DbgPrint("NtReadFile RVA = %p \n", get_rva);
// 函数分别传入 [模块路径,函数名,标志=0] 返回该导出函数的ID下标
ULONG64 get_id = GetRvaFromModuleName(L"\\SystemRoot\\system32\\ntoskrnl.exe", "NtReadFile", 0);
DbgPrint("NtReadFile ID = %d \n", get_id);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
编译并运行程序,分别获取到ntoskrnl.exe
模块内NtReadFile
函数的RVA,Index索引,调用效果如下;
第二个函数GetModuleNameFromRVA()
则实现传入RVA或者函数Index序号,解析出函数名,具体实现方法与如上函数基本一致,仅仅只是在过滤时做了调整。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
// 根据传入的函数RVA或Index下标,获取该函数的函数名
PCHAR GetModuleNameFromRVA(WCHAR *wzFileName, ULONG64 uRVA, INT Flag)
{
// 加载内核模块
PVOID BaseAddress = LoadKernelFile(wzFileName);
// 取出导出表
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeaders;
PIMAGE_SECTION_HEADER pSectionHeader;
ULONGLONG FileOffset;
PIMAGE_EXPORT_DIRECTORY pExportDirectory;
// DLL内存数据转成DOS头结构
pDosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
// 取出PE头结构
pNtHeaders = (PIMAGE_NT_HEADERS)((ULONGLONG)BaseAddress + pDosHeader->e_lfanew);
// 判断PE头导出表是否为空
if (pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_EN