Popular Post trancexx Posted September 30, 2014 Popular Post Posted September 30, 2014 (edited) GetModuleFunc.h1. IntroductionThis writing describes in detail method for retrieving the address of exported function for loaded module without using any available API on either 32bit, 64bit or ARM based Windows systems. Structures definitions are taken from Microsoft SDK 7.1, unless otherwise specified.Loaded module is searched by name, not path. The code is written in form of function that has two parameters, WCHAR pointer to the module name and CHAR pointer to the function name, written in C++ and compiled using Microsoft Visual Studio Express 2013 for Windows Desktop. Basic knowledge of C++ is assumed.Attached GetModuleFunc.h has the full code for the function.2. NT_TIBStructure defined inside winnt.h. It's the staring point for the algorithm. It includes self-referencing field - Self pointer, offset of which is used on non-ARM systems to read Thread Environment Block data.typedef struct _NT_TIB { struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; PVOID StackBase; PVOID StackLimit; PVOID SubSystemTib; #if defined(_MSC_EXTENSIONS) union { PVOID FiberData; DWORD Version; }; #else PVOID FiberData; #endif PVOID ArbitraryUserPointer; struct _NT_TIB *Self; } NT_TIB; typedef NT_TIB *PNT_TIB;2.1. TEBThread Environment Block is chunk of memory filled with various information about the thread. TEB is defined inside winternl.h as:typedef struct _TEB { PVOID Reserved1[12]; PPEB ProcessEnvironmentBlock; PVOID Reserved2[399]; BYTE Reserved3[1952]; PVOID TlsSlots[64]; BYTE Reserved4[8]; PVOID Reserved5[26]; PVOID ReservedForOle; // Windows 2000 only PVOID Reserved6[4]; PVOID TlsExpansionSlots; } TEB, *PTEB;After the executable is loaded by the Windows PE loader and before the thread starts running, TEB is saved to fs(x86) or gs(x64 flavor) processor register. ARM systems use different technique which utilize coprocessors scheme (it's unclear whether the coprocessor is real hardware component or emulated). Self field of NT_TIB is the TEB pointer for the current thread.Even not officially documented, this behavior is observed on/for all available Windows operating systems with NT kernel.Acquiring pointer to the TEB is done using Microsoft specific compiler intrinsics:#include <winnt.h> #include <winternl.h> #if defined(_M_X64) // x64 auto pTeb = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD>(&static_cast<NT_TIB*>(nullptr)->Self))); #elif defined(_M_ARM) // ARM auto pTeb = reinterpret_cast<PTEB>(_MoveFromCoprocessor(15, 0, 13, 0, 2)); // CP15_TPIDRURW #else // x86 auto pTeb = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<NT_TIB*>(nullptr)->Self))); #endifAmong others, one of the fields inside the TEB is pointer to the PEB (Process Environment Block).3. PEBProcess Environment Block is memory area filled with information about a process. PEB is defined inside winternl.h as:typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; PVOID Reserved4[3]; PVOID AtlThunkSListPtr; PVOID Reserved5; ULONG Reserved6; PVOID Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; PVOID Reserved9[45]; BYTE Reserved10[96]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved11[128]; PVOID Reserved12[1]; ULONG SessionId; } PEB, *PPEB;Pointer to the PEB is read from the TEB:auto pPeb = pTeb->ProcessEnvironmentBlock;3.1. PEB_LDR_DATAContains information about the loaded modules for the process. Ldr field of the PEB points to PEB_LDR_DATA structure, defined inside winternl.h as:typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA;Pointer to the PEB_LDR_DATA is read from the PEB:auto pLdrData = pPeb->Ldr;3.2. LIST_ENTRYInMemoryOrderModuleList field of the PEB_LDR_DATA is doubly-linked list that contains the loaded modules for the process, defined inside winnt.h as:typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Flink; struct _LIST_ENTRY *Blink; } LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;auto pModListHdr = &pLdrData->InMemoryOrderModuleList;4. LDR_DATA_TABLE_ENTRYEach item in the list is a pointer to an LDR_DATA_TABLE_ENTRY structure, defined inside winternl.h as:typedef struct _LDR_DATA_TABLE_ENTRY { PVOID Reserved1[2]; LIST_ENTRY InMemoryOrderLinks; PVOID Reserved2[2]; PVOID DllBase; PVOID Reserved3[2]; UNICODE_STRING FullDllName; BYTE Reserved4[8]; PVOID Reserved5[3]; union { ULONG CheckSum; PVOID Reserved6; } DUMMYUNIONNAME; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;DllBase field is the base address of the loaded module.This stucture doesn't give wanted info for the module, being its name. One option is to read FullDllName which includes full path and extract module name from it. However, some independent authors give slightly different definition which include another field - BaseDllName.Modified LDR_DATA_TABLE_ENTRY struct can be defined, including BaseDllName field and freed from superfluous fields. InMemoryOrderLinks will be iterated, so that field is the top of the struct:typedef struct _LDR_DATA_TABLE_ENTRY { /*LIST_ENTRY InLoadOrderLinks;*/ LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderList; PVOID DllBase; PVOID EntryPoint; PVOID Reserved3; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;4.1. IterationGoing through the items in the list is straightforward. The last item points to the first, meaning the end is reached, hence it can be written:for (auto pModListCurrent = pModListHdr->Flink; pModListCurrent != pModListHdr; pModListCurrent = pModListCurrent->Flink) { // Get current module in list auto pModEntry = reinterpret_cast<PLDR_DATA_TABLE_ENTRY>(pModListCurrent); //... }4.2. Reading Module NameThis data is stored in form of UNICODE_STRING. winternl.h definition is:typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING;Module name lookup is case insensitive. Lengths specified inside UNICODE_STRING represent bytes, which means number of WCHAR characters is half of the numbers.One of the ways to make case insensitive comparison of the specified module name and listed one is to turn both to uppercase before comparing them:for (int i = 0; i < pModEntry->BaseDllName.Length / 2 /* length is in bytes */; ++i) { if (sModuleName[i] == '\0') // the end of the string break; else if ((sModuleName[i] & ~' ') != (pModEntry->BaseDllName.Buffer[i] & ~' ')) // case-insensitive break; else if (i == iLenModule - 1) // gone through all characters and they all matched { //... the rest of the code } }iLenModule is length of the wanted module name. It's get by counting number of characters inside the string until null-terminator is encountered:int iLenModule = 0; for (; sModuleName[iLenModule]; ++iLenModule);Comparison written in this manner allows for matching function argument L"kernel32" to listed L"kernel32.dll", which mimics to a decent degree (not completely for brevity) behavior of GetModuleHandle WinAPI function. In case of two different loaded modules whose names differs only in extensions, first listed is matched.5. PE format walkthroughThe Portable Executable (PE) format is a file format for executables, object code, DLLs, etc... It describes how and where inside the file the executable code is, import table, export table, resources, and every other data needed for loader.Exported functions are listed inside the Export Table. Reaching export table is done in few steps parsing the PE data.5.1. IMAGE_DOS_HEADERThe matching module's DllBase points to the first byte of the loaded image. PE starts with legacy DOS header defined inside winnt.h as:typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;Therefore it can be written:auto pImageDOSHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(pModEntry->DllBase);e_lfanew is offset to a NT header.5.2. IMAGE_NT_HEADERSAnother area of PE is NT header. This is effectively the starting point of the portable executable format description. Definition and the size of it depends on bitness. For 32bit it's:typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;...and 64bit version is:typedef struct _IMAGE_NT_HEADERS64 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;5.3. IMAGE_NT_HEADERSOptionalHeader field is another structure discribing in detail PE file. It's directly followed by number of IMAGE_DATA_DIRECTORY structures. The exact number of these structures is saved inside IMAGE_NT_HEADERS as NumberOfRvaAndSizes field.For 32bit PE IMAGE_NT_HEADERS is defined as:expandcollapse popuptypedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;...and for 64bit version it's:typedef struct _IMAGE_OPTIONAL_HEADER64 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; ULONGLONG ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; ULONGLONG SizeOfStackReserve; ULONGLONG SizeOfStackCommit; ULONGLONG SizeOfHeapReserve; ULONGLONG SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;PE files generated by Microsoft tools allways create IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16) IMAGE_DATA_DIRECTORY structures, 15 of which are documented in this order (winnt.h):#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor5.4. IMAGE_DATA_DIRECTORYDefinition is:typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;It can now be written:auto pExport = reinterpret_cast<PIMAGE_DATA_DIRECTORY>(&pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);VirtualAddress field is RVA of the directory counting from the first byte (base) of the loaded module. If both VirtualAddress and Size fields are filled then the module exports functions.5.5. IMAGE_EXPORT_DIRECTORYDefinition is (winnt.h):typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; // RVA from base of image DWORD AddressOfNames; // RVA from base of image DWORD AddressOfNameOrdinals; // RVA from base of image } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;Base is ordinal value of the first exported function.NumberOfFunctions is overall number of exported functions from the module.NumberOfNames is number of functions exported only by name.AddressOfFunctions is RVA of the array of RVAs of exported functions addresses.AddressOfNames is RVA of the array of RVAs of exported functions names.AddressOfNameOrdinals is RVA of the array of WORD values each representing index of function exported by name, into the array of addresses.It's:auto pExports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<ULONG_PTR>(pImageDOSHeader) + pExport->VirtualAddress);6. Getting function RVAEvery exported function is accessible by odinal value. Functions exported by name are also accessible by name.Finding function by its ordinal value is fairly simple and fast. The lowest ordinal value is Base field of IMAGE_EXPORT_DIRECTORY struct. The highest ordinal value is get by adding the number of exported functions to that number, minus one of course. If the specified ordinal value is within this range, RVA is read from the array of functions addresses:if (iOrdinal) // function is wanted by its ordinal value { // Check to see if valid ordinal value is specified if (iOrdinal >= pExports->Base && iOrdinal < pExports->Base + pExports->NumberOfFunctions) dwExportRVA = pdwBufferAddress[iOrdinal - pExports->Base]; }In case of functions exported by name, name lookup needs to be performed.The code is:// Array of functions names auto pdwBufferNames = reinterpret_cast<LPDWORD>(reinterpret_cast<ULONG_PTR>(pImageDOSHeader) + pExports->AddressOfNames); // Array of functions indexes into array of addresses auto pwBufferNamesOrdinals = reinterpret_cast<LPWORD>(reinterpret_cast<ULONG_PTR>(pImageDOSHeader) + pExports->AddressOfNameOrdinals);And then the loop:// Loop through all functions exported by name for (DWORD j = 0; j < pExports->NumberOfNames; ++j) { // Read the listed function name auto sFunc = reinterpret_cast<LPCSTR>(reinterpret_cast<ULONG_PTR>(pImageDOSHeader) + pdwBufferNames[j]); //... }When the name of the function is matched (case sensitive) the RVA of the function will be read from pdwBufferAddress array at index read from pwBufferNamesOrdinals at loop counter value index:dwExportRVA = pdwBufferAddress[pwBufferNamesOrdinals[j]];6.1. Export ForwardingRVA of the function will resolve fonction's pointer. However there is one special case when the RVA offset points to a value inside the exports section and not to the function body which is normally found in some other sections of PE.When that happens, RVA will resolve to a null-terminated ASCII string value. This is called Export Forwarding. RVA is then replaced by the RVA value of the resolved function.if (dwExportRVA > pExport->VirtualAddress && dwExportRVA < pExport->VirtualAddress + pExport->Size) { // Read forwarded data. auto sForwarder = reinterpret_cast<LPCSTR>(reinterpret_cast<ULONG_PTR>(pImageDOSHeader) + dwExportRVA); //... }The format of the forwarding string is: ModuleName.FunctionName or ModuleName.#OrdinalValueTo resolve the RVA of the new exported function a recursive call to this function will be used. ModuleName has to be wide string. WCHAR buffer is allocated and all characters from ModuleName portion of forwarded string copied to it:WCHAR sForwarderDll[MAX_PATH]; // Reinterpret WCHAR buffer as CHAR one auto sForwarderDll_A = reinterpret_cast<CHAR*>(sForwarderDll); // Now go through all characters for (int iPos = 0; sForwarder[iPos]; ++iPos) { // Fill WCHAR buffer reading/copying from CHAR one sForwarderDll_A[2 * iPos] = sForwarder[iPos]; // copy character sForwarderDll_A[2 * iPos + 1] = '\0'; if (sForwarder[iPos] == '.') { sForwarderDll[iPos] = '\0'; // null-terminate the ModuleName string break; } }In case forwarding string specifies function name, pointer to that string is simply a pointer to a character following the dot.For OrdinalValue version the presence of hashtek character after the dot has to be checked and the hashtag string converted to integer value before recursive call made.The full code for this is:expandcollapse popup// Allocate big enough buffer for the new module name WCHAR sForwarderDll[MAX_PATH]; LPCSTR sForwarderFunc = nullptr; DWORD dwForwarderOrdinal = 0; // Reinterpret WCHAR buffer as CHAR one auto sForwarderDll_A = reinterpret_cast<CHAR*>(sForwarderDll); // Now go through all characters for (int iPos = 0; sForwarder[iPos]; ++iPos) { // Fill WCHAR buffer reading/copying from CHAR one sForwarderDll_A[2 * iPos] = sForwarder[iPos]; // copy character sForwarderDll_A[2 * iPos + 1] = '\0'; if (sForwarder[iPos] == '.') { sForwarderDll[iPos] = '\0'; // null-terminate the ModuleName string ++iPos; if (sForwarder[iPos] == '#') { ++iPos; // skip # character // OrdinalValue is hashtag, convert ASCII string to integer value for (; sForwarder[iPos]; ++iPos) { dwForwarderOrdinal *= 10; dwForwarderOrdinal += (sForwarder[iPos] - '0'); } if (dwForwarderOrdinal > MAX_ORDINAL) // something is wrong return nullptr; // Reinterpret the ordinal value as string sForwarderFunc = reinterpret_cast<LPSTR>(dwForwarderOrdinal); break; } else { sForwarderFunc = &sForwarder[iPos]; // FunctionName follows the dot break; } } }6.2. FinalizingOnce funcion address RVA is get, it's added to the base address and returned from the function:return reinterpret_cast<LPVOID>(reinterpret_cast<ULONG_PTR>(pImageDOSHeader) + dwExportRVA);7. ExampleThe attached zip contains two executables compiled from the source of 1K-Mandelbrot project, written by Emil Persson. The source had no explicit License Agreement. It's modified not to use WinAPI, rather to use method desribed here to call functions from used dlls and then compiled.Beautiful examples of visualisation of complex calculations, done in efficient way using OpenGL. Requirement is OpenGL 2.0.Third example is compiled for ARM. It's simple analog Direct2D clock, the original code of which is released under Artistic License/GPL by vckzdd.GetModuleFunc_Examples.zip8. ConclusionThis method isn't usually used by executables ran from user mode. It should be avoided used for production software, because it ommits taking ownership of critical section object used by windows during load/unload actions of the module, which could result in any kind of unhandled exception.Limited speed tests show that it's faster than standard GetModuleHandle/GetProcAddress method.Mimicking WinAPI behavior is achieved to a high level for valid input, with omitted special error handling and reporting. The only major difference is unsupported full-path processing.8.1. Anti-Virus Software considerationsThis method enables compiling PE files with empty imports directory. In combination with accessing fs register at TEB/PEB offset it has been observed that 18.2% of AV scanners tend to flag 32bit executables, containing no code other than this function, as malware.64 bit and ARM executables compiled from the same source never get flagged.References:Microsoft Corporation: Microsoft Portable Executable and Common Object File Format Specification, Revision 6.0Matt Pietrek: Under The Hood - http://www.microsoft.com/msj/archive/s2ce.aspxAn In-Depth Look into the Win32 Portable Executable File Format - http://msdn.microsoft.com/en-us/magazine/bb985992.aspxAn In-Depth Look into the Win32 Portable Executable File Format, Part 2 - http://msdn.microsoft.com/en-us/magazine/cc301808.aspxMark Russinovich, David A. Solomon, Alex Ionescu : Microsoft Windows Internals, 6th editionVirusTotal: Web Service - https://www.virustotal.com/Emil Persson: 1K-Mandelbrot - http://www.humus.name/index.php?page=3D&ID=85vckzdd: directxcode - https://code.google.com/p/directxcode/source/browse/#svn/Direct2D/Clock Edited October 9, 2014 by trancexx Mobius, Ascend4nt, funkey and 9 others 12 ♡♡♡ . eMyvnE
UEZ Posted September 30, 2014 Posted September 30, 2014 (edited) I have absolutely no idea what you are talking (writing) about but the Mandelbrot demo is cool which seems to be based on the 1kb Mandelbrot version. I wondered why a fan has started on my notebook while the demo is running although the CPU usage is accordingly very low until I found out that the calculation is done by the GPU (ok, you said it in 8. Example already which I've overseen first). But a very nice documentation I need probably several weeks to understand what you are talking about here... Your skills are far beyond mine and that's terrifying but good to know. Br, UEZ Edited September 30, 2014 by UEZ czardas 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Ascend4nt Posted September 30, 2014 Posted September 30, 2014 Nice article describing how one can use alternate methods to find DLL export addresses. I'm curious why you posted this here? You could have easily create a blog I've done this export lookup in Assembly threads before, as you probably know. One source of inspiration I used for doing that was this article, which uses assembly and hash lookups. (I don't use hashes myself) Also, for anyone interested in seeing whats in the TEB and PEB in more detail, try the GUI's out in the Processes and Threads UDF in my signature. iamtheky 1 My contributions: Performance Counters in Windows - Measure CPU, Disk, Network etc Performance | Network Interface Info, Statistics, and Traffic | CPU Multi-Processor Usage w/o Performance Counters | Disk and Device Read/Write Statistics | Atom Table Functions | Process, Thread, & DLL Functions UDFs | Process CPU Usage Trackers | PE File Overlay Extraction | A3X Script Extract | File + Process Imports/Exports Information | Windows Desktop Dimmer Shade | Spotlight + Focus GUI - Highlight and Dim for Eyestrain Relief | CrossHairs (FullScreen) | Rubber-Band Boxes using GUI's (_GUIBox) | GUI Fun! | IE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) | Magnifier (Vista+) Functions UDF | _DLLStructDisplay (Debug!) | _EnumChildWindows (controls etc) | _FileFindEx | _ClipGetHTML | _ClipPutHTML + ClipPutHyperlink | _FileGetShortcutEx | _FilePropertiesDialog | I/O Port Functions | File(s) Drag & Drop | _RunWithReducedPrivileges | _ShellExecuteWithReducedPrivileges | _WinAPI_GetSystemInfo | dotNETGetVersions | Drive(s) Power Status | _WinGetDesktopHandle | _StringParseParameters | Screensaver, Sleep, Desktop Lock Disable | Full-Screen Crash Recovery Wrappers/Modifications of others' contributions: _DOSWildcardsToPCRegEx (original code: RobSaunder's) | WinGetAltTabWinList (original: Authenticity) UDF's added support/programming to: _ExplorerWinGetSelectedItems | MIDIEx UDF (original code: eynstyne) (All personal code/wrappers centrally located at Ascend4nt's AutoIT Code)
iamtheky Posted October 1, 2014 Posted October 1, 2014 (edited) Holy crap I dont understand crap about this crap. The demo is very nice, and the 100% pass rate for 64-bit against AV is interesting, is there a limit to the type of payload you can sneak by with? Edited October 1, 2014 by boththose ,-. .--. ________ .-. .-. ,---. ,-. .-. .-. .-. |(| / /\ \ |\ /| |__ __||| | | || .-' | |/ / \ \_/ )/ (_) / /__\ \ |(\ / | )| | | `-' | | `-. | | / __ \ (_) | | | __ | (_)\/ | (_) | | .-. | | .-' | | \ |__| ) ( | | | | |)| | \ / | | | | | |)| | `--. | |) \ | | `-' |_| (_) | |\/| | `-' /( (_)/( __.' |((_)-' /(_| '-' '-' (__) (__) (_) (__)
jvanegmond Posted October 1, 2014 Posted October 1, 2014 Which versions of Windows did you try this on? Need any help testing on others? github.com/jvanegmond
Danyfirex Posted October 1, 2014 Posted October 1, 2014 Very used in malware developement. Saludos Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
czardas Posted October 1, 2014 Posted October 1, 2014 (edited) The wordy title of this thread reminds me of the long titles in 'Science and Supercomputing in Europe' - 2007 Report, I posted in chat. Quite a mouthful indeed. Edited October 1, 2014 by czardas operator64 ArrayWorkshop
trancexx Posted October 2, 2014 Author Posted October 2, 2014 Which versions of Windows did you try this on? Need any help testing on others?Windows 7 and 8.1.If you have Windows RT and know how to run unauthorised app there, I could add code for it too and write small app to test with.@Ascend4nt thanks for the link. And it's here just because, I guess. And maybe because I was told by few people that this place is dumb and have nothing to show. I said yes, but there are some smart people with enormous capacity around. Plus, there is possibility it will make me look smarter than I am, which is kind of appealing. Danyfirex, funkey and JohnOne 3 ♡♡♡ . eMyvnE
AdmiralAlkex Posted October 5, 2014 Posted October 5, 2014 Interesting code. I like how the example is synchronized when you run it multiple times. Windows 7 and 8.1.If you have Windows RT and know how to run unauthorised app there, I could add code for it too and write small app to test with.I could test it for you. I was thinking about resetting my Surface anyway so I guess I could downgrade to 8.0 for a while. .Some of my scripts: ShiftER, Codec-Control, Resolution switcher for HTC ShiftSome of my UDFs: SDL UDF, SetDefaultDllDirectories, Converting GDI+ Bitmap/Image to SDL Surface
trancexx Posted October 5, 2014 Author Posted October 5, 2014 Interesting code. I like how the example is synchronized when you run it multiple times. I could test it for you. I was thinking about resetting my Surface anyway so I guess I could downgrade to 8.0 for a while.Excellent. Here's one small app compiled for ARM, using the function, with no imports:Direct2dClock.zip ♡♡♡ . eMyvnE
AdmiralAlkex Posted October 7, 2014 Posted October 7, 2014 Works beautifully! jvanegmond and trancexx 2 .Some of my scripts: ShiftER, Codec-Control, Resolution switcher for HTC ShiftSome of my UDFs: SDL UDF, SetDefaultDllDirectories, Converting GDI+ Bitmap/Image to SDL Surface
trancexx Posted October 7, 2014 Author Posted October 7, 2014 Mexico? Excelentemente senor! Oh dios mio, voy a actualizar el post original. Vaya con dios mi hermoso. AdmiralAlkex and Danyfirex 2 ♡♡♡ . eMyvnE
deck_bsd Posted August 1, 2015 Posted August 1, 2015 Hello, Sorry for re up this thread. I have a little question. why didn't you do it like this ? for example :auto pPeb = reinterpret_cast<PPEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PTEB>(nullptr)->ProcessEnvironmentBlock)));orDWORD offset = 0x30; auto pPeb = reinterpret_cast<PPEB>(__readfsdword(offset));Well for the last one i can understand. But why not like the first one ? you don't need TEB or TIB structure I also have one last question.Why can you pass from a TIB structure to a TEB structure ? there are not the same :/ so why not using TEB directly ? i mean, in this line for example :auto pTeb = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PNT_TIB>(nullptr)->Self)));You start from PNT_TIB to finish with PTEB. How is it possible ? is that mean on the FS segment, there is a TEB structure , not a TIB ? Best regards
Danyfirex Posted August 1, 2015 Posted August 1, 2015 (edited) Hello, Sorry for re up this thread. I have a little question. why didn't you do it like this ? for example :auto pPeb = reinterpret_cast<PPEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PTEB>(nullptr)->ProcessEnvironmentBlock)));orDWORD offset = 0x30; auto pPeb = reinterpret_cast<PPEB>(__readfsdword(offset));Well for the last one i can understand. But why not like the first one ? you don't need TEB or TIB structure I also have one last question.Why can you pass from a TIB structure to a TEB structure ? there are not the same :/ so why not using TEB directly ? i mean, in this line for example :auto pTeb = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PNT_TIB>(nullptr)->Self)));You start from PNT_TIB to finish with PTEB. How is it possible ? is that mean on the FS segment, there is a TEB structure , not a TIB ? Best regardswhy not just 0x30. Because it's just for x86 architecture.It's because PNT_TIB it's the first field of TEB.TIB and TEB are same. Thread Environment Block (TEB) or Thread Information Block (TIB)Saludos Edited August 1, 2015 by Danyfirex Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
deck_bsd Posted August 2, 2015 Posted August 2, 2015 Yes , that's why i said ok for the 0x30 to not using it.But this line works right ? :auto pPeb = reinterpret_cast<PPEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PTEB>(nullptr)->ProcessEnvironmentBlock)));It's shorter.Yes TEB and TIB are the same in documentation, but the structure is different in the code. I found why you can convert TIB to TEB. It's because at the begining of the TEB structure you have a TIB structure as first field
Danyfirex Posted August 2, 2015 Posted August 2, 2015 Yes , that's why i said ok for the 0x30 to not using it.But this line works right ? :auto pPeb = reinterpret_cast<PPEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PTEB>(nullptr)->ProcessEnvironmentBlock)));It's shorter.Yes TEB and TIB are the same in documentation, but the structure is different in the code. I found why you can convert TIB to TEB. It's because at the begining of the TEB structure you have a TIB structure as first field NT_TIB is not a TIB/TEB. It's a part of TEB/TIB.That Line Should not. "Alone". Because You first need to fill your structure. as Topic say here#include <winnt.h> #include <winternl.h> #if defined(_M_X64) // x64 auto pTeb = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD>(&static_cast<NT_TIB*>(nullptr)->Self))); #elif defined(_M_ARM) // ARM auto pTeb = reinterpret_cast<PTEB>(_MoveFromCoprocessor(15, 0, 13, 0, 2)); // CP15_TPIDRURW #else // x86 auto pTeb = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<NT_TIB*>(nullptr)->Self))); #endifSaludos Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
deck_bsd Posted August 3, 2015 Posted August 3, 2015 NT_TIB is not a TIB/TEB. It's a part of TEB/TIB.That Line Should not. "Alone". Because You first need to fill your structure. as Topic say here#include <winnt.h> #include <winternl.h> #if defined(_M_X64) // x64 auto pTeb = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD>(&static_cast<NT_TIB*>(nullptr)->Self))); #elif defined(_M_ARM) // ARM auto pTeb = reinterpret_cast<PTEB>(_MoveFromCoprocessor(15, 0, 13, 0, 2)); // CP15_TPIDRURW #else // x86 auto pTeb = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<NT_TIB*>(nullptr)->Self))); #endifSaludosYes , it shoudn't be alone but like this :#if defined(_M_X64) // x64 auto pPeb = reinterpret_cast<PPEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PTEB>(nullptr)->ProcessEnvironmentBlock))); #elif defined(_M_ARM) // ARM auto pTeb = reinterpret_cast<PTEB>(_MoveFromCoprocessor(15, 0, 13, 0, 2)); // CP15_TPIDRURW #else // x86 auto pPeb = reinterpret_cast<PPEB>(__readfsdword(reinterpret_cast<DWORD>(&static_cast<PTEB>(nullptr)->ProcessEnvironmentBlock))); #endif
trancexx Posted August 3, 2015 Author Posted August 3, 2015 Hm, I explained every step in detail. Of course things can be writen differently, but following available documentation and being very strict with structures definitions and read fields while avoiding possible shortucts, is what often makes difference between good and bad implementation. Wouldn't you agree?I could have also used hardcoded offests to read data, and everything would be working. But that's not how things shoud be done because forward compatibility would have been lost, if nothing else. ♡♡♡ . eMyvnE
JohnOne Posted August 16, 2016 Posted August 16, 2016 Quick question if you will trancexx (or anyone else with the knowledge) Could this function be adapted to get TEB address of remote process thread? I'm currently using the dodgy NtQueryInformationThread and a load of hacky crap from around the internet. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
trancexx Posted August 16, 2016 Author Posted August 16, 2016 4 hours ago, JohnOne said: Quick question if you will trancexx (or anyone else with the knowledge) Could this function be adapted to get TEB address of remote process thread? I'm currently using the dodgy NtQueryInformationThread and a load of hacky crap from around the internet. Dodgy how? Just go with it. It's been done before, and works just fine if proper privileges are set for your process and thread accessed with correct flags ...as far as I know. ♡♡♡ . eMyvnE
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now