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);
Related
I am trying to read the CLI header (also known as the COR20 structure) from an executable coded in C#, in C++, to view its contents.
This is what I've been trying to do, and the "Header" structure has wrong values within itself: the "cb" attribute should always be 0x48, but in my case it's a much higher value, hinting that I am casting wrong data inside it, thus I am not casting the CLI header's data inside it.
Here's the code:
HANDLE fHandle = CreateFileA("C:\\Users\\MyUser\\OneDrive\\Documenti\\Desktop\\schifo\\Test2Lol.exe",
GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
DWORD fSize = GetFileSize(fHandle, 0);
BYTE* fBuffer = (BYTE*)VirtualAlloc(0, fSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ReadFile(fHandle, fBuffer, fSize, 0, 0);
PIMAGE_DOS_HEADER Dos = (PIMAGE_DOS_HEADER)fBuffer;
PIMAGE_NT_HEADERS Nt = (PIMAGE_NT_HEADERS)(fBuffer + Dos->e_lfanew);
PIMAGE_OPTIONAL_HEADER Opt = &Nt->OptionalHeader;
PIMAGE_FILE_HEADER File = &Nt->FileHeader;
PIMAGE_DATA_DIRECTORY CLRLocation = &Opt->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
PIMAGE_SECTION_HEADER Current = IMAGE_FIRST_SECTION(Nt);
PIMAGE_SECTION_HEADER CLR = 0;
for (int i = File->NumberOfSections; i != 0; i--, Current++)
{
if (Current->VirtualAddress = CLRLocation->VirtualAddress && Current->VirtualAddress + Current->SizeOfRawData > CLRLocation->VirtualAddress)
CLR = Current;
}
PIMAGE_COR20_HEADER Header = (PIMAGE_COR20_HEADER)CLR;
return 0;
My objective is to find the CLI header inside an executable, and the way inside the code is not the correct way, plus I couldn't find much around the internet.
I've tried ATA_PASS_THROUGH_EX or ATA_PASS_THROUGH_DIRECT in DeviceIoControl() function with ATA command SECURITY_SET_PASSWORD but it always failed with GetLastError()=87 (invalid parameter). But ATA command IDENTIFY always succeed.
OS Environment: Windows 8.1 64bit, Visual Studio 2010, my application has Administrator privillage.
My goal is issue SECURITY ERASE UNIt like this page in the 64bit Windows 8.1: https://ata.wiki.kernel.org/index.php/ATA_Secure_Erase
Like above web page, when I tried using 'hdparm' in the ubuntu live CD to issue secure erase has been no problem with same hardware, and same SSD.
Would you please guide me what's wrong with my code?
m_h = CreateFile("\\\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if ( m_h == INVALID_HANDLE_VALUE )
return 0;
#if 1
char buffer[512 + sizeof(ATA_PASS_THROUGH_EX)] = { 0 };
ATA_PASS_THROUGH_EX& PTE = *(ATA_PASS_THROUGH_EX *)buffer;
PTE.Length = sizeof(PTE);
PTE.DataTransferLength = 512;
PTE.DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
PTE.TimeOutValue = 10;
PTE.AtaFlags = ATA_FLAGS_DATA_OUT | ATA_FLAGS_DRDY_REQUIRED;
IDEREGS* ir = (IDEREGS*)PTE.CurrentTaskFile;
ir->bCommandReg = 0xF1;
strcpy(buffer + sizeof(ATA_PASS_THROUGH_EX) + 2, "test");
DWORD bytes = 0;
if (DeviceIoControl(m_h, IOCTL_ATA_PASS_THROUGH, &buffer, sizeof(buffer), &buffer, sizeof(buffer), &bytes, 0) == 0 ) {
DWORD er = GetLastError();
printf("error: %d\n", GetLastError());
return false;
}
#else
DWORD dataSize = sizeof(ATA_PASS_THROUGH_DIRECT) + 512;
ATA_PASS_THROUGH_DIRECT* pPTD = (ATA_PASS_THROUGH_DIRECT*) VirtualAlloc(NULL, dataSize, MEM_COMMIT, PAGE_READWRITE);
pPTD->Length = sizeof(ATA_PASS_THROUGH_DIRECT);
pPTD->DataTransferLength = 512;
pPTD->DataBuffer = ((char*)pPTD) + sizeof(ATA_PASS_THROUGH_DIRECT); // sizeof(ATA_PASS_THROUGH_DIRECT);
pPTD->TimeOutValue = 10;
pPTD->AtaFlags = ATA_FLAGS_DATA_OUT | ATA_FLAGS_DRDY_REQUIRED;
pPTD->CurrentTaskFile[1] = 0x01;
pPTD->CurrentTaskFile[6] = 0xF1;
strcpy( ((char*)pPTD->DataBuffer) + 2, "test");
DWORD bytes = 0;
if (!DeviceIoControl(m_h, IOCTL_ATA_PASS_THROUGH_DIRECT, pPTD, dataSize, pPTD, dataSize, &bytes, NULL)) {
printf("error: %d\n", GetLastError());
return false;
}
#endif
return true;
I think these ATA command blocked by OS: SECURITY SET PASSWORD, SECURITY ERASE UNIT. Because I did successfully running above program at the Windows 7 32bit and Windows 7 64bit but in Windows 8 (32bit/64bit) and Windows 10 (32bit/64bit), the same program shows invalid parameter error(error code 87).
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.
I'm trying to build a PE viewer in C++ and it seems to crash if i try to output the names of the libraries in the Import Directory Table. It seems that I am not getting the correct pointers for the DLLs that are used by the program.
HANDLE handle = CreateFile("messagebox.exe",GENERIC_READ,0,0,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
DWORD size = GetFileSize(handle,NULL);
PVOID virtualpointer = VirtualAlloc(NULL,size,MEM_COMMIT,PAGE_READWRITE);
state = ReadFile(handle,virtualpointer,size,&byteread,NULL);
CloseHandle(handle);
PIMAGE_NT_HEADERS ntheaders = PIMAGE_NT_HEADERS(PCHAR(vpointer) +
PIMAGE_DOS_HEADER(vpointer)->e_lfanew);
handle = GetCurrentProcess();
DWORD EntryAddr = ntheaders->OptionalHeader.ImageBase +
ntheaders->OptionalHeader.AddressOfEntryPoint;
DWORD importdir =
(DWORD) &(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
DWORD va = (DWORD)(ntheaders->OptionalHeader.ImageBase) +
((PIMAGE_DATA_DIRECTORY)dwValueB)->VirtualAddress;
LPSTR libname[128];
int i =0;
while(((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->Name)
{
// get DLL name
libname[i] = (LPSTR)(nt->OptionalHeader.ImageBase +
((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->Name);
i++;
}
To read the names of the libraries in the Import Directory Table, you can do the following:
Get the file's memory-mapped base address.
Get pointer to IMAGE_NT_HEADERS structure.
Get pointer to IMAGE_SECTION_HEADER structure.
DataDirectory is the final 128 bytes of OptionalHeader, which in turn is the final member of the PE header IMAGE_NT_HEADERS.
The structure has 2 members which contain the location and size of the data structure.
If you want to look up information about the dll names, you first find the RVA (Relative Virtual Address) of the Import Directory from the Data Directory, find that address in the raw section data and now you have an array of IMAGE_IMPORT_DESCRIPTOR. Get the member of this array that relates to mapped image by inspecting the strings pointed to by the Name fields.
I will not describe structure of Portable Executable File Format, but you can look at the following links:
Peering Inside the PE
Microsoft Systems Journal
Some variables in your code are not declared and this is confusing, but sticking to your skeleton code I wrote it so that it meets to your question.
DWORD Rva2Offset(DWORD rva,PIMAGE_SECTION_HEADER psh,PIMAGE_NT_HEADERS pnt);
int _tmain(int argc, _TCHAR* argv[])
{
LPCWSTR fNmae=L"C:\\Windows\\system32\\notepad.exe";
HANDLE handle=CreateFile(fNmae/*"messagebox.exe"*/, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
DWORD byteread,size=GetFileSize(handle, NULL);
PVOID virtualpointer=VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
ReadFile(handle, virtualpointer, size, &byteread, NULL);
CloseHandle(handle);
// Get pointer to NT header
PIMAGE_NT_HEADERS ntheaders=(PIMAGE_NT_HEADERS)(PCHAR(virtualpointer) + PIMAGE_DOS_HEADER(virtualpointer)-> e_lfanew);
PIMAGE_SECTION_HEADER pSech=IMAGE_FIRST_SECTION(ntheaders);//Pointer to first section header
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor; //Pointer to import descriptor
__try
{
if(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size != 0)/*if size of the table is 0 - Import Table does not exist */
{
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)virtualpointer +\
Rva2Offset(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,pSech,ntheaders));
LPSTR libname[256];
size_t i=0;
// Walk until you reached an empty IMAGE_IMPORT_DESCRIPTOR
while(pImportDescriptor->Name != NULL)
{
printf("Library Name :");
//Get the name of each DLL
libname[i]=(PCHAR)((DWORD_PTR)virtualpointer + Rva2Offset(pImportDescriptor->Name,pSech,ntheaders));
printf("%s\n", libname[i]);
pImportDescriptor++; //advance to next IMAGE_IMPORT_DESCRIPTOR
i++;
}
}
else
{
printf("No Import Table!\n");
return 1;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode())
{
printf("Exception: EXCEPTION_ACCESS_VIOLATION\n");
return 1;
}
}
if(virtualpointer)
VirtualFree(virtualpointer, size, MEM_DECOMMIT);
return 0;
}
/*Convert Virtual Address to File Offset */
DWORD Rva2Offset(DWORD rva,PIMAGE_SECTION_HEADER psh,PIMAGE_NT_HEADERS pnt)
{
size_t i = 0;
PIMAGE_SECTION_HEADER pSeh;
if(rva == 0)
{
return (rva);
}
pSeh = psh;
for(i = 0; i < pnt->FileHeader.NumberOfSections; i++)
{
if(rva >= pSeh->VirtualAddress && rva < pSeh->VirtualAddress +
pSeh->Misc.VirtualSize)
{
break;
}
pSeh++;
}
return (rva - pSeh->VirtualAddress + pSeh->PointerToRawData);
}
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;
}