PIMAGE_EXPORT_DIRECTORY - Memory Access Error - c++

I'm trying to find the RVA for loadlibrary in kernel32.dll. I've read a couple documents on parsing PE Headers but I can't seem to find out why my pointer to the export directory seems invalid.
hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
err = GetLastError();
return err;
}
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == 0)
{
err = GetLastError();
CloseHandle(fileName);
return err;
}
lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
if (lpFileBase == 0)
{
err = GetLastError();
CloseHandle(fileName);
CloseHandle(hFileMapping);
return err;
}
dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
pNTHeader = (PIMAGE_NT_HEADERS)((BYTE*)dosHeader + dosHeader->e_lfanew);
base = (DWORD64)dosHeader;
Here I open the file, everything seems fine, when I run through here wit the debugger.
exportsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
exportsEndRVA = exportsStartRVA + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
Here I successfully access the DataDirectory to get the VirtualAddress and Size of the Export Directory.
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned i;
for (i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++)
{
// Is the RVA within this section?
if ((exportsStartRVA >= section->VirtualAddress) &&
(exportsStartRVA < (section->VirtualAddress + section->Misc.VirtualSize)))
break;
}
I go through all the sections till I get a section header that encloses the exportsStartRVA. Now "section" pointer to the Section Header for the export directory.
exportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)base + exportsStartRVA + section->PointerToRawData - section->VirtualAddress);
Here I get a pointer to the Export Directory.
PDWORD pfunctions = (PDWORD)((PBYTE)base + (DWORD64)exportDir->AddressOfFunctions + header->PointerToRawData - header->VirtualAddress);
PDWORD ordinals = (PDWORD)((PBYTE)base + (DWORD64)exportDir->AddressOfNameOrdinals + header->PointerToRawData - header->VirtualAddress);
PSTR* name = (PSTR*)((PBYTE)base + (DWORD64)exportDir->AddressOfNames + header->PointerToRawData - header->VirtualAddress);
PSTR funcName;
for (unsigned i = 0; i < (DWORD64)exportDir->NumberOfNames; i++)
{
funcName = name[i];
}
edit: Problem lies within my dereferencing I think, the funcName doesn't actually give me anything other than a Memory Access Error.

AddressOfNames is a RVA to a list of RVAs to string names not a RVA to a list of strings.

Related

Find the name of the Imported DLLs using PE Headers

A Few days back I have started with Windows System Programming using c++. Hence, thought of building a utility to grab the PE Headers of an exe file.
And now I am stuck with the Image_Import_descriptor structure.
What I want is to get the names of the DLL files(modules) imported by the exe. And below is the code I am using to get those names:
DWORD Image_Import_Descriptor_addr = (DWORD)ntHeader + (DWORD)sizeof(ntHeader->FileHeader) + (DWORD)ntHeader->FileHeader.SizeOfOptionalHeader + (DWORD)ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
importImageDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)Image_Import_Descriptor_addr;
To get the RVA of the name:
DWORD name = importImageDescriptor->Name;
printf("\n\n\n\t\t (((Module Name)): %X", name);
Gives an output:
4778B00
Hope untill now everything was fine technically.
However, my motive is to print the DLL names(like kernel32.dll).
Can anyone help me out how to get the names of the DLL ?
My workarounds:
LPCSTR snames = (LPCSTR)name;
printf("\n\n\n\t\t (((Module Name)): %s", *snames);
But this is giving me an error: Access Violation
I am getting confused with the pointers and Datatype conversions. A help is much appreciated.
Got the technique from 'ired' security blogs. Below is the working code.
HANDLE h_File = CreateFile(L"testing.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!h_File) {
printf("\nERROR : Could not open the file specified\n");
}
//Mapping Given EXE file to Memory
HANDLE hMapObject = CreateFileMapping(h_File, NULL, PAGE_READONLY, 0, 0, NULL);
LPVOID basepointer = (char*)MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0);
//PIMAGE_DOS_HEADER dos_header;
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)basepointer;
printf("Magic number - %X\n", dos_header->e_magic);
printf("DOS HEADER: IMAGE NT HEADER offset(Relative Address) - %X\n", dos_header->e_lfanew); //DOS header working fine...
//PIMAGE_NT_HEADERS ntHeader;
PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)((DWORD)basepointer + dos_header->e_lfanew);
printf("NT HEADER: Signature %x\n", nt_header->Signature);
PIMAGE_FILE_HEADER file_header = (PIMAGE_FILE_HEADER)((DWORD)basepointer + dos_header->e_lfanew + sizeof(nt_header->Signature));
printf("FILE HEADER: Machine %x\n", file_header->Machine);
PIMAGE_OPTIONAL_HEADER optional_header = (PIMAGE_OPTIONAL_HEADER)((DWORD)basepointer + dos_header->e_lfanew + sizeof(nt_header->Signature) + sizeof(nt_header->FileHeader));
printf("OPTIONAL HEADER: Image Base %x\n", optional_header->ImageBase);
PIMAGE_SECTION_HEADER section_header = (PIMAGE_SECTION_HEADER)((DWORD)basepointer + dos_header->e_lfanew + sizeof(nt_header->Signature) + sizeof(nt_header->FileHeader) + sizeof(nt_header->OptionalHeader));
DWORD numberofsections = file_header->NumberOfSections;
printf("Section Header: Number of Sections %x\n", file_header->NumberOfSections);
for (int j = 0; j < optional_header->NumberOfRvaAndSizes;j++) {
printf("Data Directory: Virtual Address: %x\t\n", optional_header->DataDirectory[j].VirtualAddress);
}
DWORD RVAimport_directory = nt_header->OptionalHeader.DataDirectory[1].VirtualAddress;
//printf("RVAimport_directory %x", RVAimport_directory);
PIMAGE_SECTION_HEADER import_section = {};
for (int i = 1; i <= numberofsections; i++, section_header++) {
printf("Section Header: Section Name %s\n", section_header->Name);
if (RVAimport_directory >= section_header->VirtualAddress && RVAimport_directory < section_header->VirtualAddress + section_header->Misc.VirtualSize) {
import_section = section_header;
}
//section_header += (DWORD)sizeof(PIMAGE_SECTION_HEADER);
}
DWORD import_table_offset = (DWORD)basepointer + import_section->PointerToRawData;
//imageBaseAddress + pointerToRawDataOfTheSectionContainingRVAofInterest + (RVAofInterest - SectionContainingRVAofInterest.VirtualAddress
importImageDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(import_table_offset + (nt_header->OptionalHeader.DataDirectory[1].VirtualAddress - import_section->VirtualAddress));
//DLL Imports
for (;importImageDescriptor->Name != 0 ; importImageDescriptor++) {
DWORD Imported_DLL = import_table_offset + (importImageDescriptor->Name - import_section->VirtualAddress);
printf("Imported DLLs: %s\n", Imported_DLL);

Crash Dump generation and analysis issues

I used the example from https://github.com/hdeldar/QtCrashDumper and made us of the same in my application. Lately for actual crashes in the application the stack trace has been a little useless.
Another question is the dmp files generated module version does not match. I have double checked the module version and it is the same however the dump file has different versions. File version is 2.8.0.4 and the dmp file has 2.08.0.4
I have looked into a few answers on stackoverflow to not understand what functions I am missing.
CrashDump Info
The KB link does not exist anymore - KB313109
My implementation
#include "CrashDumpDef.h"
#include "version.h"
#ifdef USE_MINI_DUMP
#include "CrashDump.h"
#include "FileSystem.h"
LPCWSTR CrashDump::m_szAppName;
LPWSTR CrashDump::m_szAppVersion;
LPWSTR CrashDump::m_szAppBuildNumber;
WCHAR CrashDump::m_szMessageText[MAX_WARNING_MESSAGE_PATH];
LPWSTR CrashDump::m_szDumpFilePath;
#define DEFAULT_MESSAGE_TEXT L"%s Designer has experienced an issue. \nCrash dump has been saved in %s."
#define MAX_DUMP_FILE_NUMBER 9999
CrashDump::CrashDump(LPCWSTR szAppName, LPCWSTR szVersion, LPCWSTR szBuildNumber)
{
// if this assert fires then you have two instances of CrashDump
// which is not allowed
Q_ASSERT(m_szAppName == NULL);
const char* sz = VER_PRODUCTVERSION_STR;
std::vector<wchar_t> vec;
size_t len = strlen(sz);
vec.resize(len + 1);
mbstowcs(&vec[0], sz, len);
const wchar_t* productVersion = &vec[0];
std::string version = VER_PRODUCTVERSION_STR;
char build = version.back();
const char* buildNum = new char(build);
std::vector<wchar_t> vec1;
size_t lenA = strlen(buildNum);
vec1.resize(lenA + 1);
mbstowcs(&vec1[0], buildNum, lenA);
const wchar_t* buildNumber = &vec1[0];
m_szAppName = szAppName ? wcsdup(szAppName) : wcsdup(L"Designer");
m_szAppVersion = productVersion ? wcsdup(productVersion) : wcsdup(productVersion);
m_szAppBuildNumber = buildNumber ? wcsdup(buildNumber) : wcsdup(buildNumber);
wcscpy(m_szMessageText, DEFAULT_MESSAGE_TEXT);
m_szDumpFilePath = NULL;
::SetUnhandledExceptionFilter(TopLevelFilter);
}
CrashDump::~CrashDump()
{
}
void CrashDump::SetVersion(LPCWSTR szVersion)
{
if (szVersion)
{
free(m_szAppVersion);
m_szAppVersion = wcsdup(szVersion);
}
}
void CrashDump::SetBuildNumber(LPCWSTR szBuildNumber)
{
if (szBuildNumber)
{
free(m_szAppBuildNumber);
m_szAppBuildNumber = wcsdup(szBuildNumber);
}
}
void CrashDump::SetDumpFilePath(LPCWSTR szFilePath)
{
free(m_szDumpFilePath);
{
m_szDumpFilePath = wcsdup(szFilePath);
}
}
LONG CrashDump::TopLevelFilter(struct _EXCEPTION_POINTERS *pExceptionInfo)
{
//::MessageBoxW(NULL, L"debugging", m_szAppName, MB_OK);
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
// firstly see if dbghelp.dll is around and has the function we need
// look next to the EXE first, as the one in System32 might be old
// (e.g. Windows 2000)
HMODULE hDll = NULL;
WCHAR szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"DBGHELP.DLL");
hDll = ::LoadLibrary(szDbgHelpPath);
}
}
if (hDll == NULL)
{
// load any version we can
hDll = ::LoadLibrary(L"DBGHELP.DLL");
}
LPCWSTR szResult = NULL;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
if (pDump)
{
WCHAR szDumpPath[_MAX_PATH];
WCHAR szDumpRootPath[_MAX_PATH];
WCHAR szScratch[_MAX_PATH];
// work out a good place for the dump file - add the path here
if (m_szDumpFilePath == NULL)
{
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"");
wcscpy(szDumpPath, szDbgHelpPath);
}
}
//else if (!GetTempPath(_MAX_PATH, szDumpPath))
std::string dmpFile = filesystem::buildFilename(QStringList()
<< QDir::toNativeSeparators(QDir::homePath()) + "\\AppData\\Roaming\\ABC\\logs\\"
).toStdString();
std::wstring wideDmpFile;
for (int i = 0; i < dmpFile.length(); ++i)
wideDmpFile += wchar_t(dmpFile[i]);
const wchar_t* szName = wideDmpFile.c_str();
wcscpy(szDumpPath, szName);
}
else
{
wcscpy(szDumpPath, m_szDumpFilePath);
}
wcscpy(szDumpRootPath, szDumpPath);
//PrintDebug(L"[CrashDump] Mini Dump file:[%s]",szDumpPath);
// ask the user if they want to save a dump file
//if (::MessageBox( NULL, _T("Crash, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
int i = 1;
WCHAR szFileNumber[_MAX_PATH];
while (hFile == INVALID_HANDLE_VALUE)
{
swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d", i);
wcscpy(szDumpPath, szDumpRootPath);
wcscat(szDumpPath, m_szAppName);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppVersion);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppBuildNumber);
wcscat(szDumpPath, szFileNumber);
wcscat(szDumpPath, L".dmp");
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
i++;
if (i > MAX_DUMP_FILE_NUMBER)
{
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
}
// create the file
if (hFile != INVALID_HANDLE_VALUE)
{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pExceptionInfo;
ExInfo.ClientPointers = NULL;
// write the dump
BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
if (bOK)
{
swprintf(szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath);
szResult = szScratch;
retval = EXCEPTION_EXECUTE_HANDLER;
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
::CloseHandle(hFile);
WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);
//PrintError(_T("%s"), csOutMessage);
::MessageBoxW(NULL, csOutMessage, m_szAppName, MB_OK);
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
}
}
else
{
szResult = L"DBGHELP.DLL too old";
}
}
else
{
szResult = L"DBGHELP.DLL not found";
}
if (szResult)
{
//PrintDebug(_T("[CrashDump] Mini Dump result:[%s]"),szResult);
}
return retval;
}
#endif

Error while reading disk

I'm creating file deletion tool, so working with raw disk access. Have made some functions to read data.
A bit sorry because posting so much code, but not sure where is the real problem.
struct Extent
{
LONGLONG ClustersCount;
LARGE_INTEGER Lcn; //lcn - logical cluster number - the offset of a cluster from some arbitary point within volume
Extent() : ClustersCount(), Lcn()
{}
Extent(LONGLONG clustersCount, LARGE_INTEGER lcn) : ClustersCount(clustersCount), Lcn(lcn)
{}
};
typedef std::vector<Extent> ExtentsVector;
bool GetFileExtentPoints(const std::wstring& filePath, ExtentsVector& output)
{
output.clear();
DWORD err = ERROR_SUCCESS;
HANDLE file = CreateFile(filePath.c_str(), FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE)
{
STARTING_VCN_INPUT_BUFFER vcnStartBuffer = {};
RETRIEVAL_POINTERS_BUFFER pointsBuffer = {};
DWORD deviceIoControlDataritten = 0;
do
{
if (DeviceIoControl(file, FSCTL_GET_RETRIEVAL_POINTERS, &vcnStartBuffer, sizeof(vcnStartBuffer), &pointsBuffer, sizeof(pointsBuffer), &deviceIoControlDataritten, NULL))
{
Extent extent(pointsBuffer.Extents->NextVcn.QuadPart - pointsBuffer.StartingVcn.QuadPart, pointsBuffer.Extents[0].Lcn);
output.push_back(extent);
CloseHandle(file);
return true;
}
if (pointsBuffer.ExtentCount == 0) //small files could be stroed in master file table, so this part shouldn't always return false
{
CloseHandle(file);
return false;
}
Extent extent(pointsBuffer.Extents->NextVcn.QuadPart - pointsBuffer.StartingVcn.QuadPart, pointsBuffer.Extents[0].Lcn);
output.push_back(extent);
vcnStartBuffer.StartingVcn = pointsBuffer.Extents->NextVcn;
}
while (ERROR_MORE_DATA == GetLastError());
CloseHandle(file);
}
return false;
}
bool PermanentDeleteFile/*for now just read...*/(const std::wstring& filePath)
{
ExtentsVector extents;
if (!GetFileExtentPoints(filePath, extents))
return false;
DWORD sectorsPerCluster = 0;
DWORD bytesPerSector = 0;
LARGE_INTEGER fileSize = {};
HANDLE file = CreateFile(filePath.c_str(), FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE)
{
TCHAR drive[] = L"?:\\";
drive[0] = filePath[0];
if (!GetDiskFreeSpace(drive, &sectorsPerCluster, &bytesPerSector, NULL, NULL))
{
CloseHandle(file);
return false;
}
if (!GetFileSizeEx(file, &fileSize))
{
CloseHandle(file);
return false;
}
CloseHandle(file);
}
LONGLONG clusterSize = sectorsPerCluster * bytesPerSector;
LONGLONG clustersCount = fileSize.QuadPart / clusterSize + ((fileSize.QuadPart % clusterSize == 0) ? 0 : 1);
TCHAR rawDrive[] = L"\\\\.\\?:";
rawDrive[4] = filePath[0];
HANDLE driveHandle = CreateFile(rawDrive, /*GENERIC_WRITE*/GENERIC_READ/**/, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (driveHandle != INVALID_HANDLE_VALUE)
{
for (ExtentsVector::iterator it = extents.begin(); it != extents.end(); ++it)
{
LARGE_INTEGER distance = {};
distance.QuadPart = it->Lcn.QuadPart * clusterSize;
BOOL b = SetFilePointerEx(driveHandle, distance, NULL, FILE_BEGIN);
if (b)
{
std::string buffer;
buffer.resize(clusterSize * it->ClustersCount);
DWORD read = 0;
BOOL B = ReadFile(driveHandle, &buffer[0], clusterSize * it->ClustersCount, &read, NULL);
B = FALSE;//here I have breakpoint and for FAT type drives buffer contains invalid data
}
else
{
CloseHandle(driveHandle);
return false;
}
}
}
return false;
}
GetFileExtentPoints should collect clusters entries and cluster chain size for latter actions according to given file.
The place where the problem is seen is in PermanentDeleteFile I have marked that place with comment.
I have tried to read all my FAT32 drive and found that data I'm looking for is in drive but in other place so, as I understand FAT uses some kind of data offset. After that read this. As I think the offset is described by first 3 bytes in drive, but don't understand how to use it. In my case it is 0xEB 0x58 0x90. Want to ask, how to decode file system header into data offset.
BTW. I'm coding with C++ and using WinAPI.
EDIT: I have change my line into distance.QuadPart = it->Lcn.QuadPart * clusterSize + 0x01000000;, this works for FAT, however I don't want to have hardcoded constants, so can someone tell, if it is always this value, or it is calculated some way.

Code injection in a MFC application

I have a Win32 application that gets the HANDLE of a MFC application. My goal is to force the MFC program not to display ASSERT error message box.
Basically, I have made a prototype that allows my Win32 application to force the MFC application to show a message box, just to check if the idea is possible. Now I need to force the MFC application not to display such ASSERT error message boxes.
Is that possible?
You can do this by intercepting the MessageBoxA/MessageBoxW function call. At a usermode level, this is typically done in one of three places:
Call site - There may be more than one call to MessageBox in your executable. You need to find the one that you want to disable. Then you can overwrite the call with code that does nothing (i.e. overwrite with nop instructions).
IAT - The Import Address Table; a table of function pointers filled in by the PE loader. Execution often (but not always) flows through here and replacing the function pointer for MessageBox can allow the MessageBox call to be redirected to some routine that does nothing.
Function entry point - The start of the MessageBox function. This can be located by GetProcAddress and the first instruction replaced with a ret.
The manipulation is done either at runtime (dynamically) or statically (binary rewriting/executable editing) with the first option being far more common. A library which can help you achieve runtime detouring is Microsoft Detours.
This is not a comprehensive list of all the possibilities, but rather the most common methods of execution redirection and detouring.
To my great regret I missed that code. However you still can do it by hands.
Download and install CFF explorer
Open your exe-file with it
Select import directory in sections explorer.
Select USER32.dll in the imported dll list
Select MessageBoxA or MessageBoxW. Edit OFT column. Write there OFT of some "harmless" function. I used GetWindowRect as example.
If you still want an appliaction to do this, I have a code with very similar functionality. It just embeds your dll into import table. You may both edit it to reach wanted result or to use it to redirect MessageBoxW call to your handler.
#include <windows.h>
#include <tchar.h>
#include "stdafx.h"
#include <stdio.h>
DWORD MapFile(HANDLE &FileMapping, LPVOID &FileBegin, const _TCHAR *exeName) {
HANDLE File = CreateFile(exeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (File == INVALID_HANDLE_VALUE) {
return GetLastError();
}
FileMapping = CreateFileMapping(File, NULL, PAGE_READWRITE, 0, 0, NULL);
CloseHandle(File);
if (!FileMapping) {
return GetLastError();
}
FileBegin = MapViewOfFile(FileMapping, FILE_MAP_WRITE, 0, 0, 0);
if (!FileBegin) {
CloseHandle(FileMapping);
return GetLastError();
}
return 0;
}
DWORD RewriteImportTable(const HANDLE FileMapping, const LPVOID FileBegin, const _TCHAR *dllName, const _TCHAR *funcName, DWORD &finalResult) {
IMAGE_DOS_HEADER* dos_header;
IMAGE_FILE_HEADER* file_header;
IMAGE_OPTIONAL_HEADER* optional_header;
IMAGE_SECTION_HEADER* section_header;
// Counting PE-header offset
dos_header = (IMAGE_DOS_HEADER*) FileBegin;
DWORD PEOffset = dos_header->e_lfanew;
file_header = (IMAGE_FILE_HEADER*) ((DWORD)FileBegin + PEOffset); // file_header must reference "PE\0"
// Checking if we work with PE
_TCHAR* PEString = "PE\0";
if (_tcscmp(PEString, (const _TCHAR*) file_header) != 0) {
printf("This file is not Portable Executable!\n");
return 666;
}
file_header = (IMAGE_FILE_HEADER *)((DWORD)file_header + sizeof(DWORD)); // Ignoring PE
optional_header = (IMAGE_OPTIONAL_HEADER *)((DWORD)file_header + sizeof(IMAGE_FILE_HEADER));
// Finding import section
DWORD ImportRVA = optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
int sectNum = -1;
// Finding import table
section_header = (IMAGE_SECTION_HEADER*) ((DWORD) optional_header + sizeof(IMAGE_OPTIONAL_HEADER));
for (int i = 0; i < (file_header->NumberOfSections); i++) {
if (ImportRVA < (section_header->VirtualAddress)) {
section_header--;
sectNum = i-1;
break;
}
section_header++;
}
if (sectNum == -1) {
printf("This program uses no external libraries! (strange)\n");
return 666;
}
// Getting address of section folowing import section
section_header++;
DWORD SectionNextToImportBegin = (DWORD)FileBegin + section_header->PointerToRawData;
section_header--;
// Getting the address of the import table
LPVOID ImportSectionBegin = (LPVOID) ((DWORD)FileBegin + section_header->PointerToRawData);
// Counting the import table offset in the import section
LPVOID ImportTable = (LPVOID)((DWORD)ImportSectionBegin + (ImportRVA - section_header->VirtualAddress));
IMAGE_IMPORT_DESCRIPTOR *DLLInfo = (IMAGE_IMPORT_DESCRIPTOR*) ImportTable;
LPVOID DLLName;
DWORD DLLCounter = 0;
while (DLLInfo->Name != NULL) {
DLLCounter++;
DLLName = (LPVOID) ((DWORD)ImportSectionBegin + ((DWORD)DLLInfo->Name - section_header->VirtualAddress));
DLLInfo++;
}
printf("Number of imported libraries: %d\n", DLLCounter);
// Counting the size of the future import table
DWORD newImportTableSize = sizeof(IMAGE_IMPORT_DESCRIPTOR) * (DLLCounter + 2);
// Finding the end of the import section
LPVOID pos = (LPVOID) (SectionNextToImportBegin - 1);
DWORD maxFree = 0;
DWORD prevPtr;
LPVOID freePtr = NULL;
// Searching for the free place
while (pos >= ImportSectionBegin) {
if (*(BYTE*)pos == 0) {
prevPtr = (DWORD) pos;
while (*(BYTE*)pos == 0) {
pos = (LPVOID) ((DWORD)pos - 1);
}
if (((DWORD)prevPtr - (DWORD)pos) > maxFree) {
maxFree = ((DWORD)prevPtr - (DWORD)pos);
freePtr = (LPVOID) ((DWORD)pos + 1);
}
}
pos = (LPVOID) ((DWORD)pos - 1);
}
// Modifying pointer: it can refer the tailing zero of some stucture
freePtr = (LPVOID) ((LPDWORD)freePtr + 1);
maxFree -= 4;
// Checking if we have enough space in the import section
if (maxFree < newImportTableSize) {
printf("Not enough free space in Import Section\n");
return 666;
}
printf("Injecting new library...\n");
// Copying old import table on the new place
memcpy(freePtr, ImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR) * DLLCounter);
// Saving everithing we need on the old place
typedef struct {
DWORD ZeroDword;
DWORD IAT;
DWORD IATEnd;
} MeanStruct;
MeanStruct patch;
patch.ZeroDword = NULL; // this is \0 for dll name
patch.IAT = ImportRVA + _tcslen(dllName) + sizeof(MeanStruct); // RVA to where list of functions begins
patch.IATEnd = NULL;
WORD Hint = 0;
IMAGE_IMPORT_BY_NAME myName;
myName.Hint = 0x00;
myName.Name[0] = 0x00;
LPDWORD zeroPtr = (LPDWORD) ImportTable;
memcpy(zeroPtr, dllName, _tcslen(dllName));
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + strlen(dllName));
memcpy(zeroPtr, &patch, sizeof(patch));
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + sizeof(patch));
finalResult = (DWORD)zeroPtr - (DWORD)ImportSectionBegin + section_header->VirtualAddress;
memcpy(zeroPtr, &Hint, sizeof(WORD));
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + sizeof(WORD));
memcpy(zeroPtr, funcName, strlen(funcName) + 1); // we have no need to write \0 into the end - this is already free space
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + strlen(funcName) + 1);
memcpy(zeroPtr, &myName, sizeof(IMAGE_IMPORT_BY_NAME));
// filling info about dll
IMAGE_IMPORT_DESCRIPTOR myDLL;
// counting RVA for IMAGE_IMPORT_BY_NAME:
DWORD IIBN_Table = ImportRVA + strlen(dllName) + sizeof(DWORD);
// function name pointer
myDLL.Characteristics = IIBN_Table;
myDLL.TimeDateStamp = NULL;
myDLL.ForwarderChain = NULL;
// dll name pointer
myDLL.Name = ImportRVA;
myDLL.FirstThunk = IIBN_Table;
// writting dll info into the new import table
LPVOID oldFreePtr = freePtr;
freePtr = (LPVOID) ((DWORD)freePtr + sizeof(IMAGE_IMPORT_DESCRIPTOR) * DLLCounter);
memcpy(freePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));
// creating list tail
myDLL.Characteristics = NULL;
myDLL.TimeDateStamp = NULL;
myDLL.ForwarderChain = NULL;
myDLL.Name = NULL;
myDLL.FirstThunk = NULL;
// writing list tail
freePtr = (LPVOID) ((DWORD)freePtr + sizeof(IMAGE_IMPORT_DESCRIPTOR));
memcpy(freePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));
// setting new import table rva
DWORD newImportTableRVA = (DWORD)oldFreePtr - (DWORD)ImportSectionBegin + section_header->VirtualAddress;
// changing DataDirectory
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = newImportTableRVA;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DLLCounter + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
// clearing non-actual values
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
return 0;
}
int _tmain(int argc, _TCHAR *argv[]) {
if (argc != 4) {
printf("Invalid arguments number!!!\n");
return 0;
}
HANDLE FileMapping;
LPVOID FileBegin;
DWORD FileMappingResult = MapFile(FileMapping, FileBegin, argv[1]);
if (0 != FileMappingResult) {
printf("Error of file mapping (%d)\n", FileMappingResult);
if (NULL != FileMapping) CloseHandle(FileMapping);
return FileMappingResult;
}
DWORD functionAddr;
DWORD RewriteImportTableResult = RewriteImportTable(FileMapping, FileBegin, argv[2], argv[3], functionAddr);
if (0 != RewriteImportTableResult) {
UnmapViewOfFile(FileBegin);
CloseHandle(FileMapping);
return 666;
}
printf("Library successfully injected!\n");
printf("Address of injected function: %X", functionAddr);
UnmapViewOfFile(FileBegin);
CloseHandle(FileMapping);
return 0;
}

CreateFileMapping for Directory

I have this function which gives the full file name(path) from the file handle. The only problem is CreateFileMapping fails for directory handles. Is there a workaround for it?
I get the handle using NtCreateFile()
ULONG status = NtCreatefile(&f, GENERIC_ALL, &oa, iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_BY_FILE_ID , NULL, 0);
printf("status: %X, handle: %x\n", status, f);
AND
BOOL CHouseKeeper::GetFileNameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR pszFilename[MAX_PATH+1];
HANDLE hFileMap;
// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
{
_tprintf(TEXT("Cannot map a file with a length of zero.\n"));
return FALSE;
}
// Create a file mapping object.
//It fails here if a directory handle is passed, it returns 0
hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
1,
NULL);
if (hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
if (GetMappedFileName (GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
{
// Translate path with device name to drive letters.
TCHAR szTemp[BUFSIZE];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(BUFSIZE-1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = _tcslen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0
&& *(pszFilename + uNameLen) == _T('\\');
if (bFound)
{
// Reconstruct pszFilename using szTempFile
// Replace device path with DOS path
TCHAR szTempFile[MAX_PATH];
StringCchPrintf(szTempFile,
MAX_PATH,
TEXT("%s%s"),
szDrive,
pszFilename+uNameLen);
StringCchCopyN(pszFilename, MAX_PATH+1, szTempFile, _tcslen(szTempFile));
}
}
}
// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // end of string
}
}
bSuccess = TRUE;
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}else {
wcout<<GetLastError()<<endl;
}
_tprintf(TEXT("File name is %s\n"), pszFilename);
return(bSuccess);
}
You can use NtQueryInformationFile with FileNameInformation to retrieve the name associated with a file handle.