Brandon
2013-03-30 15:32:57
The below code I wrote when creating a decompiler and injector. The first function will get all information about a process given the name. The second function will get all modules loaded by a process, their handles, names, paths, address, etc.. It can be taken further to find out all functions exported in a module.
Finally, the third function reads any file and prints all information about that file. It's a PE reader. Took me an extremely long amount of time to write these and I hope they come in useful for some of you who wish to see things done at the lowest level.
Originally, I wrote some of the functions in ASM but C++ will be easier for all of us to read and more useable.
These functions work for BOTH x32 and x64 bit processes and any type of file/module. The functions can be modified to HIDE modules and files within a process.. Such is the works of a virus and I will not explain how to modify them to do such things.
These API's are mostly undocumented API's so there won't be much information on it online at all. Most of it was guess work except for the PE reader.
Examples on notepad:



Enjoy!
Finally, the third function reads any file and prints all information about that file. It's a PE reader. Took me an extremely long amount of time to write these and I hope they come in useful for some of you who wish to see things done at the lowest level.
Originally, I wrote some of the functions in ASM but C++ will be easier for all of us to read and more useable.
These functions work for BOTH x32 and x64 bit processes and any type of file/module. The functions can be modified to HIDE modules and files within a process.. Such is the works of a virus and I will not explain how to modify them to do such things.
These API's are mostly undocumented API's so there won't be much information on it online at all. Most of it was guess work except for the PE reader.
Examples on notepad:



Enjoy!
#include <winternl.h>
#include <windows.h>
#include <TlHelp32.h>
#include <iostream>
struct Library
{
HMODULE Module = nullptr;
Library(const char* LibraryName)
{
Module = LoadLibrary(LibraryName);
}
~Library()
{
FreeLibrary(Module);
}
};
typedef struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
typedef NTSTATUS NTAPI (*pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
PROCESSENTRY32 GetProcessInfo(const char* ProcessName)
{
void* hSnap = nullptr;
PROCESSENTRY32 Proc32 = {0};
if((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE)
return Proc32;
Proc32.dwSize = sizeof(PROCESSENTRY32);
while(Process32Next(hSnap, &Proc32))
{
if(!stricmp(ProcessName, Proc32.szExeFile))
{
CloseHandle(hSnap);
return Proc32;
}
}
CloseHandle(hSnap);
Proc32 = {0};
return Proc32;
}
void ListModuleInfo(std::string Process)
{
SIZE_T dwBytesRead = 0;
PROCESS_BASIC_INFORMATION PBI = {0};
PROCESSENTRY32 ProcessInfo = GetProcessInfo(Process.c_str());
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, false, ProcessInfo.th32ProcessID);
Library NTDLL("ntdll.dll");
pNtQueryInformationProcess NtQIP = (pNtQueryInformationProcess) GetProcAddress(NTDLL.Module, "NtQueryInformationProcess");
if (NT_SUCCESS(NtQIP(ProcessHandle, ProcessBasicInformation, &PBI, sizeof(PBI), reinterpret_cast<DWORD*>(&dwBytesRead))))
{
PEB_LDR_DATA LdrData;
LDR_MODULE LdrModule;
PPEB_LDR_DATA pLdrData = nullptr;
char* LdrDataOffset = reinterpret_cast<char*>(PBI.PebBaseAddress) + offsetof(PEB, Ldr);
ReadProcessMemory(ProcessHandle, LdrDataOffset, &pLdrData, sizeof(pLdrData), &dwBytesRead);
ReadProcessMemory(ProcessHandle, pLdrData, &LdrData, sizeof(LdrData), &dwBytesRead);
LIST_ENTRY* Head = LdrData.InMemoryOrderModuleList.Flink;
LIST_ENTRY* Node = Head;
do
{
if (ReadProcessMemory(ProcessHandle, reinterpret_cast<char*>(Node) - sizeof(LIST_ENTRY), &LdrModule, sizeof(LdrModule), &dwBytesRead))
{
if (LdrModule.BaseAddress)
{
std::wstring BaseDllName(LdrModule.BaseDllName.Length / sizeof(WCHAR), 0);
std::wstring FullDllName(LdrModule.FullDllName.Length / sizeof(WCHAR), 0);
ReadProcessMemory(ProcessHandle, LdrModule.BaseDllName.Buffer, &BaseDllName[0], LdrModule.BaseDllName.Length, &dwBytesRead);
ReadProcessMemory(ProcessHandle, LdrModule.FullDllName.Buffer, &FullDllName[0], LdrModule.FullDllName.Length, &dwBytesRead);
std::cout<<"BaseAddress: "<< LdrModule.BaseAddress<<std::endl;
std::cout<<"Entry-Point: " << LdrModule.EntryPoint<<std::endl;
std::wcout<<"Base DLL-Name: "<< BaseDllName<<std::endl;
std::wcout<<"Full DLL-Name: "<< FullDllName<<std::endl;
std::cout<<"Reference Count: "<< LdrModule.LoadCount<<std::endl;
std::cout<<"Image Size: "<< LdrModule.SizeOfImage<<std::endl;
std::cout<<"Time Date Stamp: "<< LdrModule.TimeDateStamp<<std::endl;
std::cout<<std::endl;
}
}
Node = LdrModule.InMemoryOrderModuleList.Flink;
}
while(Head != Node);
}
CloseHandle(ProcessHandle);
}
void PrintPEInfo(std::string FilePath)
{
IMAGE_DOS_HEADER* pDosHeader;
IMAGE_NT_HEADERS* pNtHeaders;
IMAGE_SECTION_HEADER* pSectionHeader;
void* FileHandle = CreateFile(FilePath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (FileHandle == INVALID_HANDLE_VALUE) return;
void* FileMapping = CreateFileMapping(FileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
void* MapView = MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0);
pDosHeader = reinterpret_cast<IMAGE_DOS_HEADER*>(MapView);
if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
std::cout<<"Valid Dos-Exe File (IMAGE_DOS_HEADER)"<<std::endl;
std::cout<<"----------------------------------------"<<std::endl;
std::cout<<"Magic Number: "<<std::hex<<pDosHeader->e_magic<<std::endl;
std::cout<<"Bytes On Last Page: "<<pDosHeader->e_cblp<<std::endl;
std::cout<<"No. Of Pages: "<<pDosHeader->e_crlc<<std::endl;
std::cout<<"Size Of Header Paragraphs: "<<pDosHeader->e_cparhdr<<std::endl;
std::cout<<"Min. Extra Paragraphs: "<<pDosHeader->e_minalloc<<std::endl;
std::cout<<"Max. Extra Paragraphs: "<<pDosHeader->e_maxalloc<<std::endl;
std::cout<<"Initial SS-Value: "<<pDosHeader->e_ss<<std::endl;
std::cout<<"Initial SP-Value: "<<pDosHeader->e_sp<<std::endl;
std::cout<<"Checksum: "<<pDosHeader->e_csum<<std::endl;
std::cout<<"Initial IP-Value: "<<pDosHeader->e_ip<<std::endl;
std::cout<<"Initial CS-Value: "<<pDosHeader->e_cs<<std::endl;
std::cout<<"File Address Relocation: "<<pDosHeader->e_lfarlc<<std::endl;
std::cout<<"Overlay Number: "<<pDosHeader->e_ovno<<std::endl;
std::cout<<"OEM Identifier: "<<pDosHeader->e_oemid<<std::endl;
std::cout<<"OEM Specific Information: "<<pDosHeader->e_oeminfo<<std::endl;
std::cout<<"RVA Address of PE-Header: "<<pDosHeader->e_lfanew<<std::endl;
std::cout<<std::endl<<std::endl;
}
pNtHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(((SIZE_T)(pDosHeader)) + pDosHeader->e_lfanew);
if(pNtHeaders->Signature == IMAGE_NT_SIGNATURE)
{
std::cout<<"Valid PE-File (IMAGE_NT_HEADER)"<<std::endl;
std::cout<<"----------------------------------------"<<std::endl;
std::cout<<"Signature: "<<pNtHeaders->Signature<<std::endl;
std::cout<<"Machine Architecture: ";
switch (pNtHeaders->FileHeader.Machine)
{
case IMAGE_FILE_MACHINE_I386:
std::cout<<"x86 "<<std::endl;
break;
case IMAGE_FILE_MACHINE_IA64:
std::cout<<"Intel Itanium"<<std::endl;
break;
case IMAGE_FILE_MACHINE_AMD64:
std::cout<<"x64 "<<std::endl;
break;
default:
std::cout<<"Unknown "<<std::endl;
break;
}
std::cout<<"Number Of Sections: "<<pNtHeaders->FileHeader.NumberOfSections<<std::endl;
std::cout<<"Time Date Stamp: "<<pNtHeaders->FileHeader.TimeDateStamp<<std::endl;
std::cout<<"Pointer To Symbol Table: "<<pNtHeaders->FileHeader.PointerToSymbolTable<<std::endl;
std::cout<<"Number Of Symbols: "<<pNtHeaders->FileHeader.NumberOfSymbols<<std::endl;
std::cout<<"Size Of Optional-Header: "<<pNtHeaders->FileHeader.SizeOfOptionalHeader<<std::endl;
std::cout<<"Characteristics: "<<std::endl<<std::endl;
WORD Characteristics[] = {IMAGE_FILE_RELOCS_STRIPPED, IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LINE_NUMS_STRIPPED, IMAGE_FILE_LARGE_ADDRESS_AWARE,
IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_DEBUG_STRIPPED, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, IMAGE_FILE_NET_RUN_FROM_SWAP, IMAGE_FILE_SYSTEM,
IMAGE_FILE_DLL, IMAGE_FILE_UP_SYSTEM_ONLY
};
for (std::size_t I = 0; I < sizeof(Characteristics)/sizeof(WORD); ++I)
{
switch (pNtHeaders->FileHeader.Characteristics & Characteristics[I])
{
case IMAGE_FILE_RELOCS_STRIPPED:
std::cout<<" Relocation information was stripped from the file."<<std::endl;
break;
case IMAGE_FILE_EXECUTABLE_IMAGE:
std::cout<<" The file is executable."<<std::endl;
break;
case IMAGE_FILE_LINE_NUMS_STRIPPED:
std::cout<<" COFF line numbers were stripped from the file."<<std::endl;
break;
case IMAGE_FILE_LARGE_ADDRESS_AWARE:
std::cout<<" The application can handle addresses larger than 2 GB."<<std::endl;
break;
case IMAGE_FILE_32BIT_MACHINE:
std::cout<<" The computer supports 32-bit words."<<std::endl;
break;
case IMAGE_FILE_DEBUG_STRIPPED:
std::cout<<" Debugging information was removed and stored separately in another file."<<std::endl;
break;
case IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP:
std::cout<<" If the image is on removable media, copy it to and run it from the swap file."<<std::endl;
break;
case IMAGE_FILE_NET_RUN_FROM_SWAP:
std::cout<<" If the image is on the network, copy it to and run it from the swap file."<<std::endl;
break;
case IMAGE_FILE_SYSTEM:
std::cout<<" The image is a system file."<<std::endl;
break;
case IMAGE_FILE_DLL:
std::cout<<" The image is a DLL file. It can't be run directly."<<std::endl;
break;
case IMAGE_FILE_UP_SYSTEM_ONLY:
std::cout<<" The file should be run only on a uniprocessor computer."<<std::endl;
break;
default:
break;
}
}
std::cout<<"\n\nOptional-Header (IMAGE_OPTIONAL_HEADER)"<<std::endl;
std::cout<<"----------------------------------------"<<std::endl;
std::cout<<"Magic Number: "<<pNtHeaders->OptionalHeader.Magic<<std::endl;
std::cout<<"Major Linker Version: "<<static_cast<int>(pNtHeaders->OptionalHeader.MajorLinkerVersion)<<std::endl;
std::cout<<"Minor Linker Version: "<<static_cast<int>(pNtHeaders->OptionalHeader.MajorLinkerVersion)<<std::endl;
std::cout<<"Code Section Size (.text): "<<pNtHeaders->OptionalHeader.SizeOfCode<<std::endl;
std::cout<<"Size Of Initialized Data: "<<pNtHeaders->OptionalHeader.SizeOfInitializedData<<std::endl;
std::cout<<"Address Of Entry Point: "<<pNtHeaders->OptionalHeader.AddressOfEntryPoint<<std::endl;
std::cout<<"Address Of Code (.code): "<<pNtHeaders->OptionalHeader.BaseOfCode<<std::endl;
#ifndef __x86_64
std::cout<<"Address Of Data (.data): "<<pNtHeaders->OptionalHeader.BaseOfData<<std::endl;
#endif
std::cout<<"Base Address Of Image: "<<pNtHeaders->OptionalHeader.ImageBase<<std::endl;
std::cout<<"Section Alignment: "<<pNtHeaders->OptionalHeader.SectionAlignment<<std::endl;
std::cout<<"FileAlignment: "<<pNtHeaders->OptionalHeader.FileAlignment<<std::endl;
std::cout<<"Major OS Version: "<<pNtHeaders->OptionalHeader.MajorOperatingSystemVersion<<std::endl;
std::cout<<"Minor OS Version: "<<pNtHeaders->OptionalHeader.MinorOperatingSystemVersion<<std::endl;
std::cout<<"Major Image Version: "<<pNtHeaders->OptionalHeader.MajorImageVersion<<std::endl;
std::cout<<"Minor Image Version: "<<pNtHeaders->OptionalHeader.MinorImageVersion<<std::endl;
std::cout<<"Major Subsystem Version: "<<pNtHeaders->OptionalHeader.MajorSubsystemVersion<<std::endl;
std::cout<<"Minor Subsystem Version: "<<pNtHeaders->OptionalHeader.MinorSubsystemVersion<<std::endl;
std::cout<<"Size Of Image: "<<pNtHeaders->OptionalHeader.SizeOfImage<<std::endl;
std::cout<<"Size Of Headers: "<<pNtHeaders->OptionalHeader.SizeOfHeaders<<std::endl;
std::cout<<"Checksum: "<<pNtHeaders->OptionalHeader.CheckSum<<std::endl;
std::cout<<"Subsystem: ";
switch (pNtHeaders->OptionalHeader.Subsystem)
{
case IMAGE_SUBSYSTEM_UNKNOWN:
std::cout<<"Unknown subsystem."<<std::endl;
break;
case IMAGE_SUBSYSTEM_NATIVE:
std::cout<<"No subsystem required (device drivers and native system processes)."<<std::endl;
break;
case IMAGE_SUBSYSTEM_WINDOWS_GUI:
std::cout<<"Windows graphical UI (GUI) subsystem."<<std::endl;
break;
case IMAGE_SUBSYSTEM_WINDOWS_CUI:
std::cout<<"Windows character-mode UI (CUI) subsystem."<<std::endl;
break;
case IMAGE_SUBSYSTEM_OS2_CUI:
std::cout<<"OS/2 CUI subsystem."<<std::endl;
break;
case IMAGE_SUBSYSTEM_POSIX_CUI:
std::cout<<"POSIX CUI subsystem."<<std::endl;
break;
case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
std::cout<<"Windows CE system."<<std::endl;
break;
case IMAGE_SUBSYSTEM_EFI_APPLICATION:
std::cout<<"Extensible Firmware Interface (EFI) application."<<std::endl;
break;
case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
std::cout<<"EFI driver with boot services."<<std::endl;
break;
case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
std::cout<<"EFI driver with run-time services."<<std::endl;
break;
case IMAGE_SUBSYSTEM_EFI_ROM:
std::cout<<"EFI ROM image."<<std::endl;
break;
case IMAGE_SUBSYSTEM_XBOX:
std::cout<<"Xbox system."<<std::endl;
break;
case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
std::cout<<"Boot application."<<std::endl;
break;
default:
break;
}
std::cout<<"Dll Characteristics: "<<std::endl<<std::endl;
WORD DllCharacteristics[] = {IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY, IMAGE_DLLCHARACTERISTICS_NX_COMPAT,
IMAGE_DLLCHARACTERISTICS_NO_ISOLATION, IMAGE_DLLCHARACTERISTICS_NO_SEH, IMAGE_DLLCHARACTERISTICS_NO_BIND, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER,
IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
};
for (std::size_t I = 0; I < sizeof(DllCharacteristics)/sizeof(WORD); ++I)
{
switch (pNtHeaders->OptionalHeader.DllCharacteristics & DllCharacteristics[I])
{
case IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE:
std::cout<<" The DLL can be relocated at load time."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY:
std::cout<<" Code integrity checks are forced."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_NX_COMPAT:
std::cout<<" The image is compatible with data execution prevention (DEP)."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_NO_ISOLATION:
std::cout<<" The image is isolation aware, but should not be isolated."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_NO_SEH:
std::cout<<" The image does not use structured exception handling (SEH)."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_NO_BIND:
std::cout<<" Do not bind the image."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_WDM_DRIVER:
std::cout<<" A WDM driver."<<std::endl;
break;
case IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE:
std::cout<<" The image is terminal server aware."<<std::endl;
break;
default:
break;
}
}
std::cout<<std::endl;
std::cout<<"Size Of Stack Reserve: "<<pNtHeaders->OptionalHeader.SizeOfStackReserve<<std::endl;
std::cout<<"Size Of Stack Commit: "<<pNtHeaders->OptionalHeader.SizeOfStackCommit<<std::endl;
std::cout<<"Size Of Heap Reserve: "<<pNtHeaders->OptionalHeader.SizeOfHeapReserve<<std::endl;
std::cout<<"Size Of Heap Commit: "<<pNtHeaders->OptionalHeader.SizeOfHeapCommit<<std::endl;
std::cout<<"Number Of Rva And Sizes: "<<pNtHeaders->OptionalHeader.NumberOfRvaAndSizes<<std::endl;
int I = 0;
std::cout<<"\n\nData Directory (IMPORT TABLE RVA):"<<std::endl;
std::cout<<"----------------------------------"<<std::endl;
for (pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders); I < pNtHeaders->FileHeader.NumberOfSections; ++pSectionHeader, ++I)
{
std::cout<<"\n\n Section Info ("<<I + 1<<" of "<<pNtHeaders->FileHeader.NumberOfSections<<")"<<std::endl;
std::cout<<" ------------------------------------"<<std::endl;
if ((pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress >= pSectionHeader->VirtualAddress) && ((pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) > pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress))
{
std::cout<<" IAT Entry Point: "<<((pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - pSectionHeader->VirtualAddress) + pSectionHeader->PointerToRawData)<<std::endl;
}
std::cout<<" Section Header Name: "<<pSectionHeader->Name<<std::endl;
std::cout<<" Actual .code or .data Size: "<<pSectionHeader->Misc.VirtualSize<<std::endl;
std::cout<<" Virtual Address(RVA): "<<pSectionHeader->VirtualAddress<<std::endl;
std::cout<<" Size Of Raw Data: "<<pSectionHeader->SizeOfRawData<<std::endl;
std::cout<<" Pointer To Raw Data: "<<pSectionHeader->PointerToRawData<<std::endl;
std::cout<<" Pointer To Relocations: "<<pSectionHeader->PointerToRelocations<<std::endl;
std::cout<<" Pointer To Line Numbers: "<<pSectionHeader->PointerToLinenumbers<<std::endl;
std::cout<<" Number Of Relocations: "<<pSectionHeader->NumberOfRelocations<<std::endl;
std::cout<<" Number Of Line Numbers: "<<pSectionHeader->NumberOfLinenumbers<<std::endl;
std::cout<<" Characteristics: ";
//For each characteristic.. switch.. sectionheader..
}
std::cout<<std::endl<<std::endl;
}
UnmapViewOfFile(MapView);
CloseHandle(FileMapping);
CloseHandle(FileHandle);
}
int main()
{
ListModuleInfo("notepad.exe");
std::cout<<"Press Enter/Return To Continue.."<<std::endl;
std::cin.get();
PrintPEInfo("C:/windows/notepad.exe");
std::cout<<"Press Enter/Return To Exit.."<<std::endl;
std::cin.get();
}