Aerosol Posted December 10, 2014 Report Posted December 10, 2014 Microsoft Windows is a modular architecture. Windows Components are split into smaller pieces known as DLL (Dynamic-Link Library) and sys files (system files). These DLL or system files are inter-related to each other and work as a team. A call from a single DLL is forwarded to another DLL function name or other inter-modular calls. Have you ever wondered how Windows API calls are implemented internally? Well, we are going to learn about the Windows internal call structure in this article.Tools Required:Windows XP machine or virtual Machine.C/C++ compiler.A Debugger like ollydbg.Understanding the executable formatAs an object file is compiled, it gets transformed into a PE (Portable Executable) file (or an exe file). Portable Executable files are well documented by Microsoft. They consist of sections and headers: these sections and headers inform the PE loader how to load the executable file by Windows. For example, some of the fields inform the loader which section is to be marked as executable and which is to be marked as data section. Size of initial heap, stack, TLS (Thread Local Storage) is also determined by PE headers.Now let’s create a minimalistic PE file and check out its headers and sections:Microsoft (R) COFF/PE Dumper Version 8.00.50727.42Copyright (C) Microsoft Corporation. All rights reserved.Dump of file sample.exePE signature foundFile Type: EXECUTABLE IMAGEFILE HEADER VALUES14C machine (x86)3 number of sections5207B239 time date stamp Sun Aug 11 21:18:09 20130 file pointer to symbol table0 number of symbolsE0 size of optional header103 characteristicsRelocations strippedExecutable32 bit word machineOPTIONAL HEADER VALUES10B magic # (PE32)8.00 linker version200 size of code400 size of initialized data0 size of uninitialized data1000 entry point (00401000)1000 base of code2000 base of data400000 image base (00400000 to 00403FFF)1000 section alignment200 file alignment4.00 operating system version0.00 image version4.00 subsystem version0 Win32 version4000 size of image400 size of headers0 checksum3 subsystem (Windows CUI)400 DLL characteristicsNo structured exception handler100000 size of stack reserve1000 size of stack commit100000 size of heap reserve1000 size of heap commit0 loader flags10 number of directories0 [ 0] RVA [size] of Export Directory2008 [ 28] RVA [size] of Import Directory0 [ 0] RVA [size] of Resource Directory0 [ 0] RVA [size] of Exception Directory0 [ 0] RVA [size] of Certificates Directory0 [ 0] RVA [size] of Base Relocation Directory0 [ 0] RVA [size] of Debug Directory0 [ 0] RVA [size] of Architecture Directory0 [ 0] RVA [size] of Global Pointer Directory0 [ 0] RVA [size] of Thread Storage Directory0 [ 0] RVA [size] of Load Configuration Directory0 [ 0] RVA [size] of Bound Import Directory2000 [ 8] RVA [size] of Import Address Table Directory0 [ 0] RVA [size] of Delay Import Directory0 [ 0] RVA [size] of COM Descriptor Directory0 [ 0] RVA [size] of Reserved DirectorySECTION HEADER #1.text name81 virtual size1000 virtual address (00401000 to 00401080)200 size of raw data400 file pointer to raw data (00000400 to 000005FF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers60000020 flagsCodeExecute ReadRAW DATA #100401000: 55 8B EC 51 C7 45 FC 00 00 00 00 68 30 10 40 00 U.ìQÇEü....h0.@.00401010: FF 15 00 20 40 00 8B 45 FC C6 00 36 33 C0 8B E5 ÿ.. @..EüÆ.63À.å00401020: 5D C3 CC CC CC CC CC CC CC CC CC CC CC CC CC CC ]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌ00401030: 55 8B EC 83 EC 08 8B 45 08 8B 08 8B 11 89 55 F8 U.ì.ì..E......Uø00401040: 81 7D F8 05 00 00 C0 75 28 A1 00 30 40 00 83 C0 .}ø...Àu(¡.0@..À00401050: 01 A3 00 30 40 00 83 3D 00 30 40 00 05 7D 09 C7 .£.0@..=.0@..}.Ç00401060: 45 FC FF FF FF FF EB 07 C7 45 FC 01 00 00 00 EB Eüÿÿÿÿë.ÇEü....ë00401070: 07 C7 45 FC 00 00 00 00 8B 45 FC 8B E5 5D C2 04 .ÇEü.....Eü.å]Â.00401080: 00 .SECTION HEADER #2.rdata name64 virtual size2000 virtual address (00402000 to 00402063)200 size of raw data600 file pointer to raw data (00000600 to 000007FF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers40000040 flagsInitialized DataRead OnlyRAW DATA #200402000: 38 20 00 00 00 00 00 00 30 20 00 00 00 00 00 00 8 ......0 ......00402010: 00 00 00 00 56 20 00 00 00 20 00 00 00 00 00 00 ....V ... ......00402020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................00402030: 38 20 00 00 00 00 00 00 4A 03 53 65 74 55 6E 68 8 ......J.SetUnh00402040: 61 6E 64 6C 65 64 45 78 63 65 70 74 69 6F 6E 46 andledExceptionF00402050: 69 6C 74 65 72 00 4B 45 52 4E 45 4C 33 32 2E 64 ilter.KERNEL32.d00402060: 6C 6C 00 00 ll..Section contains the following imports:KERNEL32.DLL402000 Import Address Table402030 Import Name Table0 time date stamp0 Index of first forwarder reference34A SetUnhandledExceptionFilterSECTION HEADER #3.data name4 virtual size3000 virtual address (00403000 to 00403003)0 size of raw data0 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbersC0000040 flagsInitialized DataRead WriteSummary1000 .data1000 .rdata1000 .textEvery PE file begins with a ‘MZ’ signature that acts as an indicator of a valid PE file.It follows up with a valid MZ section header (where the DOS error program is also located) and will pop out a message if the PE file runs under MS DOS. After the DOS stub pointer is present (which gives out the offset to the PE header),0000003C D8000000 DD 000000D8 ; Offset to PE signatureIt’s the RVA from the beginning of MZ header.We can calculate RV by using the following formula:RVA = Virtual Address – Base addressIf we reach to the offset of the PE signature, we would have four bytes for the PE signature plus IMAGE_PE header.The following examples are basic but still important points of this header:000000D8 50 45 00 00 ASCII “PE” ; PE signature (PE)000000DC 4C01 DW 014C ; Machine = IMAGE_FILE_MACHINE_I386000000DE 0500 DW 0005 ; NumberOfSections = 5000000E0 8F9BC44E DD 4EC49B8F ; TimeDateStamp = 4EC49B8FThe machine specifies the architecture for which it was made. NumberOfSections specifies number of sections this portable executable has. TimeDateStamp is the time_t struct value for the date it was compiled.Other values like ‘numberofsection’ gives you the list numbers of sections inside a PE file.This can be enumerated using the IMAGE_DATA_DIRECTORY structure.One other important member of the PE format is the AddressOfEntryPoint. This RVA points towards the Entry point of the program from where the execution starts.Following code can be used to get the entry point of the executableunsigned int AddrSPSize(unsigned char *PEfile){ FILE *fp = fopen((const char *)PEfile, "rb"); IMAGE_DOS_HEADER DosHdr = {0}; IMAGE_FILE_HEADER FileHdr = {0}; IMAGE_OPTIONAL_HEADER OptHdr = {0}; fread(&DosHdr, sizeof(IMAGE_DOS_HEADER), 0x01, fp); fseek(fp, (unsigned int)DosHdr.e_lfanew + 4,SEEK_SET); fseek(fp, sizeof(IMAGE_FILE_HEADER), SEEK_CUR); fread( &OptHdr, sizeof(IMAGE_OPTIONAL_HEADER) , 0x01, fp); fclose(fp); return(OptHdr.SizeOfImage);}Thread Information Block (TIB)The Tread information block consists of a plethora of information regarding the current thread. “Flowing” is the definition of the thread information block and its structures. The base of TEB is located at FS:[0] segment register .struct TEBtypedef struct _TEB{ NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; ULONG LastErrorValue; ULONG CountOfOwnedCriticalSections; PVOID CsrClientThread; PVOID Win32ThreadInfo; ULONG User32Reserved[26]; ULONG UserReserved[5]; PVOID WOW32Reserved; ULONG CurrentLocale; ULONG FpSoftwareStatusRegister; VOID * SystemReserved1[54]; LONG ExceptionCode; PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; UCHAR SpareBytes1[36]; ULONG TxFsContext; GDI_TEB_BATCH GdiTebBatch; CLIENT_ID RealClientId; PVOID GdiCachedProcessHandle; ULONG GdiClientPID; ULONG GdiClientTID; PVOID GdiThreadLocalInfo; ULONG Win32ClientInfo[62]; VOID * glDispatchTable[233]; ULONG glReserved1[29]; PVOID glReserved2; PVOID glSectionInfo; PVOID glSection; PVOID glTable; PVOID glCurrentRC; PVOID glContext; ULONG LastStatusValue; UNICODE_STRING StaticUnicodeString; WCHAR StaticUnicodeBuffer[261]; PVOID DeallocationStack; VOID * TlsSlots[64]; LIST_ENTRY TlsLinks; PVOID Vdm; PVOID ReservedForNtRpc; VOID * DbgSsReserved[2]; ULONG HardErrorMode; VOID * Instrumentation[9]; GUID ActivityId; PVOID SubProcessTag; PVOID EtwLocalData; PVOID EtwTraceData; PVOID WinSockData; ULONG GdiBatchCount; UCHAR SpareBool0; UCHAR SpareBool1; UCHAR SpareBool2; UCHAR IdealProcessor; ULONG GuaranteedStackBytes; PVOID ReservedForPerf; PVOID ReservedForOle; ULONG WaitingOnLoaderLock; PVOID SavedPriorityState; ULONG SoftPatchPtr1; PVOID ThreadPoolData; VOID * * TlsExpansionSlots; ULONG ImpersonationLocale; ULONG IsImpersonating; PVOID NlsCache; PVOID pShimData; ULONG HeapVirtualAffinity; PVOID CurrentTransactionHandle; PTEB_ACTIVE_FRAME ActiveFrame; PVOID FlsData; PVOID PreferredLanguages; PVOID UserPrefLanguages; PVOID MergedPrefLanguages; ULONG MuiImpersonation; WORD CrossTebFlags; ULONG SpareCrossTebBits: 16; WORD SameTebFlags; ULONG DbgSafeThunkCall: 1; ULONG DbgInDebugPrint: 1; ULONG DbgHasFiberData: 1; ULONG DbgSkipThreadAttach: 1; ULONG DbgWerInShipAssertCode: 1; ULONG DbgRanProcessInit: 1; ULONG DbgClonedThread: 1; ULONG DbgSuppressDebugMsg: 1; ULONG SpareSameTebBits: 8; PVOID TxnScopeEnterCallback; PVOID TxnScopeExitCallback; PVOID TxnScopeContext; ULONG LockCount; ULONG ProcessRundown; UINT64 LastSwitchTime; UINT64 TotalSwitchOutTime; LARGE_INTEGER WaitReasonBitMap;} TEB, *PTEB;One more important structure that resides inside the TEB is the process environment block, which has some really interesting fields:typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId;}LDR consists of loaded modules by the executable during runtime. The second variable BeingDebugged is set if the process is being debugged otherwise 0.We can also enumerate the list of loaded process modules using this structure.Internal Windows Kernel call Structure.Now let’s look at how internal calls to Windows Kernel take place. For this we will use CreateFileA as an example.HANDLE File = CreateFile(“File”, FILE_READ_DATA , FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,The above code statement calls CreateFileA in kernel32.DLL, after getting inside CreateFileA in kernel32.DLL, let’s see what the subsequent calls are being made after that.As we can see that there are two internal calls being made in kernel32!CreateFileA.Let’s look at the first one which is located at 7C80E2A4This call takes one argument as file name.After examining the rtlinitansistring, we can form structs and functions in C equivalent codestruct __unknwon{ short len; short max_len; void *buffer;}unknown;sturct __unknown rtlinitansistring ( struct unknown, unsigned char *buffer){ unkown.len = 0; unknwon.buffer = buffer; if ( buffer == 0) return unknown; while(*buffer) { unknown.len++; buffer++; } return unknown;}This function initializes the ANSI string and stores them in a struct.After this call, another function is called but before it a check regarding OEM string is made7C80E2C5 CMP DWORD PTR DS:[7C8836E0],0This function basically converts a ANSI string to UNICODE oneAfter finishing up with Character conversion, CreateFileW is called with File name in unicode rest of the parameters are kept same.Inside CreateFileW it will always first check if parameter Mode is CREATE_ALWAYS, which in our case, is.Mode = CREATE_ALWAYS7C810988 . 48 DEC EAX7C810989 . 0F84 C9060000 JE kernel32.7C811058In that case it will set its variable as 57C811058 > C745 F8 050000>MOV DWORD PTR SS:[EBP-8],5 After that it again calls RtlInitUnicodeString7C8109A2 . 56 PUSH ESI ; /Arg27C8109A3 . 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] ; |7C8109A6 . 50 PUSH EAX ; |Arg17C8109A7 . FF15 4010807C CALL DWORD PTR DS:[<&ntDLL.RtlInitUnicod>; RtlInitUnicodeStringUp to now, lots of heap memory was allocated. Code that will de-allocate all unused memory is called; which happens to be present at 0x7C810A0EFinally, after the call to NtCreateFile is made, we land inside ntDLL.DLL sys call dispatcher7C90D682 >/$ B8 25000000 MOV EAX,257C90D687 |. BA 0003FE7F MOV EDX,7FFE03007C90D68C |. FF12 CALL DWORD PTR DS:[EDX] ; ntDLL.KiFastSystemCall7C90D68E . C2 2C00 RETN 2C0×25 is the SYS Call Number for Create File7C90EB8B >/$ 8BD4 MOV EDX,ESP7C90EB8D |. 0F34 SYSENTERReferences:Windows NT/2000 Native API Reference: Gary Nebbett: 9781578701995: Amazon.com: Bookshttp://www.amazon.com/dp/0735625301RtlAnsiStringToUnicodeString function receieves strict __unicode as one of its parameters.Source Quote