Wednesday, January 28, 2009

Resolve function call using IAT

As we disassemble functions, sometimes we might have the following display:

0:017> uf ftpaccess!IFTPCreateSystem
ftpaccess!IFTPCreateSystem:
00b2cba0 56 push esi
00b2cba1 57 push edi
00b2cba2 6a20 push 20h
00b2cba4 33ff xor edi,edi
00b2cba6 e8f7160000 call ftpaccess!CreateLicenseInfo+0x3a2 (00b2e2a2)
00b2cbab 8bf0 mov esi,eax
00b2cbad 83c404 add esp,4
00b2cbb0 3bf7 cmp esi,edi
00b2cbb2 7435 je ftpaccess!IFTPCreateSystem+0x49 (00b2cbe9)

ftpaccess!IFTPCreateSystem+0x14:
00b2cbb4 8d4608 lea eax,[esi+8]
00b2cbb7 50 push eax
00b2cbb8 c706dc09b300 mov dword ptr [esi],offset ftpaccess!CreateLicenseInfo+0x2adc (00b309dc)
00b2cbbe ff150401b300 call dword ptr [ftpaccess!CreateLicenseInfo+0x2204 (00b30104)]
00b2cbc4 687073b300 push offset ftpaccess!CreateLicenseInfo+0x9470 (00b37370)
00b2cbc9 897e04 mov dword ptr [esi+4],edi
00b2cbcc ff156400b300 call dword ptr [ftpaccess!CreateLicenseInfo+0x2164 (00b30064)]
00b2cbd2 57 push edi
00b2cbd3 57 push edi
00b2cbd4 e887d8ffff call ftpaccess!InitializeLicensing (00b2a460)
00b2cbd9 8b16 mov edx,dword ptr [esi]
00b2cbdb 8b02 mov eax,dword ptr [edx]
00b2cbdd 83c408 add esp,8
00b2cbe0 8bce mov ecx,esi
00b2cbe2 ffd0 call eax
00b2cbe4 5f pop edi
00b2cbe5 8bc6 mov eax,esi
00b2cbe7 5e pop esi
00b2cbe8 c3 ret
...

There are four function calls. Two of them are pretty straightforward:
00b2cba6 e8f7160000 call ftpaccess!CreateLicenseInfo+0x3a2 (00b2e2a2)
00b2cbd4 e887d8ffff call ftpaccess!InitializeLicensing (00b2a460).

The other two are function pointers and can not be resolved by just looking at disassembled code:
00b2cbbe ff150401b300 call dword ptr [ftpaccess!CreateLicenseInfo+0x2204 (00b30104)]
00b2cbcc ff156400b300 call dword ptr [ftpaccess!CreateLicenseInfo+0x2164 (00b30064)].

However, we do know that these two functions' addresses are 00b30104 and 00b30064, respectively. To resolve which functions those addresses refer to, we could look them up from Import Address Table in the module headers.

First, retrieve the starting address of the specified module:
0:017> lm m ftpaccess
start end module name
00b20000 00b3b000 ftpaccess (export symbols) C:\Program Files\Ipswitch\Common\ftpaccess.dll


Second, dump the headers for the specified module:
0:017> !dh 00b20000
...
14680 [ DF] address [size] of Export Directory
135A0 [ DC] address [size] of Import Directory
18000 [ 5E4] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
19000 [ 11BC] address [size] of Base Relocation Directory
10310 [ 1C] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
122D8 [ 40] address [size] of Load Configuration Directory
0 [ 0] address [size] of Bound Import Directory
10000 [ 2E0] address [size] of Import Address Table Directory
0 [ 0] address [size] of Delay Import Directory
0 [ 0] address [size] of COR20 Header Directory
0 [ 0] address [size] of Reserved Directory
...

Third, dump the content of IAT directory,
0:017> dps 00b20000+10000 00b20000+10000+2E0
00b30000 77dd6fef ADVAPI32!RegQueryValueExW
00b30004 77dd6a9f ADVAPI32!RegOpenKeyExW
00b30008 77ddd757 ADVAPI32!RegSetValueExW
00b3000c 77dfba25 ADVAPI32!RegCreateKeyW
00b30010 77dd7edd ADVAPI32!RegEnumValueW
00b30014 77dd6c17 ADVAPI32!RegCloseKey
00b30018 00000000
00b3001c 0fb7b1e0 IPSLIBEAY32!EVP_EncryptInit
00b30020 0fb79920 IPSLIBEAY32!EVP_aes_256_cfb128
00b30024 0fb7a200 IPSLIBEAY32!EVP_CIPHER_CTX_init
00b30028 0fb7a530 IPSLIBEAY32!EVP_DecryptUpdate
00b3002c 0fb7b1a0 IPSLIBEAY32!EVP_DecryptInit
00b30030 0fb7a350 IPSLIBEAY32!EVP_EncryptUpdate
00b30034 0fb79420 IPSLIBEAY32!EVP_DigestFinal
00b30038 0fb78e10 IPSLIBEAY32!EVP_DigestUpdate
00b3003c 0fb78de0 IPSLIBEAY32!EVP_DigestInit
00b30040 0fb7b700 IPSLIBEAY32!EVP_sha256
00b30044 0fb7ab80 IPSLIBEAY32!EVP_CIPHER_CTX_cleanup
00b30048 0fb10950 IPSLIBEAY32!idea_set_decrypt_key
00b3004c 0fb7a180 IPSLIBEAY32!EVP_des_cbc
00b30050 0fb20940 IPSLIBEAY32!EVP_rc2_cfb64
00b30054 0fb10920 IPSLIBEAY32!idea_set_encrypt_key
00b30058 0fb78ef0 IPSLIBEAY32!EVP_MD_CTX_cleanup
00b3005c 0fb10230 IPSLIBEAY32!idea_cfb64_encrypt
00b30060 00000000
00b30064 7c8097f6 KERNEL32!InterlockedIncrement
00b30068 7c809bd7 KERNEL32!CloseHandle
00b3006c 7c8300ca KERNEL32!CancelIo
00b30070 7c8315b4 KERNEL32!GetOverlappedResult
00b30074 7c80a0ed KERNEL32!WaitForMultipleObjects
00b30078 7c83161f KERNEL32!ReadDirectoryChangesW
00b3007c 7c80a739 KERNEL32!CreateEventW
00b30080 7c8107f0 KERNEL32!CreateFileW
00b30084 7c802530 KERNEL32!WaitForSingleObject
00b30088 7c80a0a7 KERNEL32!SetEvent
00b3008c 7c80980a KERNEL32!InterlockedDecrement
00b30090 7c9010e0 ntdll!RtlLeaveCriticalSection
00b30094 7c80ae30 KERNEL32!GetProcAddress
00b30098 7c80aedb KERNEL32!LoadLibraryW
00b3009c 7c80f37e KERNEL32!SetCurrentDirectoryW
00b300a0 7c80b907 KERNEL32!GetCurrentDirectoryW
00b300a4 7c809c88 KERNEL32!MultiByteToWideChar
00b300a8 7c80a164 KERNEL32!WideCharToMultiByte
00b300ac 7c80be46 KERNEL32!lstrlenA
00b300b0 7c809a99 KERNEL32!lstrlenW
00b300b4 7c90fe01 ntdll!RtlGetLastWin32Error
00b300b8 7c810b69 KERNEL32!CompareFileTime
00b300bc 7c810bac KERNEL32!SystemTimeToFileTime
00b300c0 7c80176f KERNEL32!GetSystemTime
00b300c4 7c835d6c KERNEL32!WritePrivateProfileStringA
00b300c8 7c81ee34 KERNEL32!WritePrivateProfileStringW
00b300cc 7c80981e KERNEL32!InterlockedExchange
00b300d0 7c85ac7c KERNEL32!OutputDebugStringA
00b300d4 7c83089d KERNEL32!CreateEventA
00b300d8 7c80932e KERNEL32!GetTickCount
00b300dc 7c801a28 KERNEL32!CreateFileA
00b300e0 7c801d7b KERNEL32!LoadLibraryA
00b300e4 7c801629 KERNEL32!DeviceIoControl
00b300e8 7c812b6e KERNEL32!GetVersionExA
00b300ec 7c80b55f KERNEL32!GetModuleFileNameA
00b300f0 7c8099a5 KERNEL32!GetACP
00b300f4 7c80a4b7 KERNEL32!QueryPerformanceCounter
00b300f8 7c813123 KERNEL32!IsDebuggerPresent
00b300fc 7c901000 ntdll!RtlEnterCriticalSection
00b30100 7c91135a ntdll!RtlDeleteCriticalSection
00b30104 7c809f81 KERNEL32!InitializeCriticalSection
00b30108 7c80b465 KERNEL32!GetModuleFileNameW
00b3010c 7c8097b8 KERNEL32!GetCurrentThreadId
00b30110 7c8099b0 KERNEL32!GetCurrentProcessId
00b30114 7c80ac6e KERNEL32!FreeLibrary
00b30118 7c8449fd KERNEL32!SetUnhandledExceptionFilter
00b3011c 7c863e6a KERNEL32!UnhandledExceptionFilter
00b30120 7c80de85 KERNEL32!GetCurrentProcess
00b30124 7c801e1a KERNEL32!TerminateProcess
00b30128 7c809832 KERNEL32!InterlockedCompareExchange
00b3012c 7c802446 KERNEL32!Sleep
00b30130 7c80a4a5 KERNEL32!GetThreadLocale
00b30134 7c80d2f2 KERNEL32!GetLocaleInfoA
00b30138 7c8017e9 KERNEL32!GetSystemTimeAsFileTime
...

With IAT, we can resolve which functions the addresses -- 00b30064 and 00b30104 refer to.

 

Tuesday, January 20, 2009

Possible error in ntdll!RtlAllocateHeap

These days, I am working on a crash dump from an escalation.

0:012> kb
ChildEBP RetAddr Args to Child
04ceb7a0 7c827d0b 77e61d1e 00000530 00000000 ntdll!KiFastSystemCallRet
04ceb7a4 77e61d1e 00000530 00000000 04ceb7e8 ntdll!NtWaitForSingleObject+0xc
04ceb814 77e61c8d 00000530 00004e20 00000000 kernel32!WaitForSingleObjectEx+0xac
04ceb828 7a0c0a43 00000530 00004e20 284e61d1 kernel32!WaitForSingleObject+0x12
04ceb858 7a0c0e89 00000530 00004e20 284e649d mscorwks!ClrWaitForSingleObject+0x24
04cebd14 7a0c2bfd 000005f8 00000530 000005f0 mscorwks!RunWatson+0x1df
04cec458 7a0c3171 04cec7a8 00000001 001edd38 mscorwks!DoFaultReportWorker+0xb62
04cec494 7a106b2d 04cec7a8 00000001 04cec7a8 mscorwks!DoFaultReport+0xc3
04cec4bc 7a10a89a 001edd38 04cec7a8 00000001 mscorwks!WatsonLastChance+0x43
04cec514 7a10a9ae 04cec780 7c35f0c3 04cec7a8 mscorwks!SaveIPFilter+0x1b5
04cec51c 7c35f0c3 04cec7a8 77ecb7c0 77e761b7 mscorwks!InternalUnhandledExceptionFilter+0x22
04cec528 77e761b7 04cec7a8 00000000 00000000 msvcr71!__CxxUnhandledExceptionFilter+0x46
04cec780 77e792a3 04cec7a8 77e61ac1 04cec7b0 kernel32!UnhandledExceptionFilter+0x12a
04cec788 77e61ac1 04cec7b0 00000000 04cec7b0 kernel32!BaseThreadStart+0x4a
04cec7b0 7c828752 04cec894 04ceffdc 04cec8b0 kernel32!_except_handler3+0x61
04cec7d4 7c828723 04cec894 04ceffdc 04cec8b0 ntdll!ExecuteHandler2+0x26
04cec87c 7c82855e 04ce6000 04cec8b0 04cec894 ntdll!ExecuteHandler+0x24
04cec87c 7c82bcd4 04ce6000 04cec8b0 04cec894 ntdll!KiUserExceptionDispatcher+0xe
04cecd98 78134d83 00620000 00000000 00000f5c ntdll!RtlAllocateHeap+0xa2a
04cecdb8 78160e30 00000f5c 00000001 035334f4 msvcr80!malloc+0x7a

The stack trace indicates that an unhandled exception has caused Dr. Watson to generate the user dump. Since kernel32!UnhandledExceptionFilter appears in the stack trace, we can use the method introduced in http://support.microsoft.com/kb/313109 to find out the exception record and switch to the context when the exception was thrown.


0:012> dt EXCEPTION_POINTERS 04cec7a8
msvcr71!EXCEPTION_POINTERS
+0x000 ExceptionRecord : 0x04cec894 _EXCEPTION_RECORD
+0x004 ContextRecord : 0x04cec8b0 _CONTEXT

0:012> .exr 0x04cec894
ExceptionAddress: 7c82bcd4 (ntdll!RtlAllocateHeap+0x00000a2a)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: fffffff8
Attempt to read from address fffffff8

0:012> .cxr 0x04cec8b0
eax=fffffff8 ebx=00000090 ecx=00000000 edx=04190e70 esi=00620178 edi=035455e0
eip=7c82bcd4 esp=04cecb7c ebp=04cecd98 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
ntdll!RtlAllocateHeap+0xa2a:
7c82bcd4 663b18 cmp bx,word ptr [eax] ds:0023:fffffff8=????
0:012> kb
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
04cecd98 78134d83 00620000 00000000 00000f5c ntdll!RtlAllocateHeap+0xa2a
04cecdb8 78160e30 00000f5c 00000001 035334f4 msvcr80!malloc+0x7a
Unable to load image C:\Program Files\Ipswitch\Common\ftplogwriter.dll, Win32 error 0n2
*** WARNING: Unable to verify timestamp for ftplogwriter.dll
04cecdd0 030b6d6f 00000f5c 29549f5d 035334f0 msvcr80!operator new+0x1d
04cece2c 79e77fd5 79e80171 04cecec8 00000000 ftplogwriter!IFTPLogWriter_Impl::LogArray+0x9f [d:\fts\ftplogwriter\src\ftplogwriter_impl.cpp @ 184]
04cece68 79e8025f 79e80277 284e1699 00000000 mscorwks!HelperMethodFrame_1OBJ::HelperMethodFrame_1OBJ+0x14
04cecfec 79f08df5 04ced190 0465dc30 00000000 mscorwks!ObjectNative::GetHashCode+0x13a
04ced0f8 79e84b26 04ced190 04ced76c 04ced140 mscorwks!COMPlusUnwindCallback+0x7c3
04ced10c 79e84962 04ced190 79f07d64 04ced76c mscorwks!Thread::MakeStackwalkerCallback+0x15
79e73940 79e730fb 79e79318 79e74034 79f0ce08 mscorwks!Thread::StackWalkFramesEx+0x396
79e73958 79e730fb 79f0ce29 79e754a8 79e730fc mscorwks!Exception::`vftable'+0x2b
7a08959d 75c08510 58026a04 e9c88bc3 fff310de mscorwks!Exception::`vftable'+0x2b
WARNING: Frame IP not in any known module. Following frames may be wrong.
7a0895a1 58026a04 e9c88bc3 fff310de 0424448b 0x75c08510
7a0895a5 e9c88bc3 fff310de 0424448b c13bc933 0x58026a04
7a0895a9 fff310de 0424448b c13bc933 08890274 0xe9c88bc3
7a0895ad 0424448b c13bc933 08890274 0824448b 0xfff310de
7a0895b1 c13bc933 08890274 0824448b 0274c13b 0x424448b
7a0895b5 08890274 0824448b 0274c13b 448b0889 0xc13bc933
7a0895b9 0824448b 0274c13b 448b0889 c13b0c24 0x8890274
7a0895bd 0274c13b 448b0889 c13b0c24 08890274 0x824448b
7a0895c1 448b0889 c13b0c24 08890274 8b000cc2 0x274c13b

So it is an access violation due to heap corruption. Obviously, the crash happened when the code tried to dereference the address pointed to by EAX. The address pointed to by EAX is quite interesting -- fffffff8.

0:012> .formats fffffff8
Evaluate expression:
Hex: fffffff8
Decimal: -8
Octal: 37777777770
Binary: 11111111 11111111 11111111 11111000
Chars: ....
Time: ***** Invalid
Float: low -1.#QNAN high 0
Double: 2.122e-314


The address is -8! The next question is how EAX gets that invalid address.

0:012>uf ntdll!RtlAllocateHeap
...
ntdll!RtlAllocateHeap+0xa05:
7c82bcb3 0fb7c3 movzx eax,bx
7c82bcb6 50 push eax
7c82bcb7 ff75e4 push dword ptr [ebp-1Ch]
7c82bcba e8fefeffff call ntdll!RtlpFindEntry (7c82bbbd)

ntdll!RtlAllocateHeap+0xa15:
7c82bcbf 8bc8 mov ecx,eax

ntdll!RtlAllocateHeap+0xa17:
7c82bcc1 898d70ffffff mov dword ptr [ebp-90h],ecx
7c82bcc7 3bf1 cmp esi,ecx
7c82bcc9 7412 je ntdll!RtlAllocateHeap+0xa33 (7c82bcdd)

ntdll!RtlAllocateHeap+0xa21:
7c82bccb 8d41f8 lea eax,[ecx-8]
7c82bcce 8985d4feffff mov dword ptr [ebp-12Ch],eax
7c82bcd4 663b18 cmp bx,word ptr [eax]
7c82bcd7 0f87de4f0000 ja ntdll!RtlAllocateHeap+0xa2f (7c830cbb)
...

From the unassembled function, it seems that EAX stores the return value from ntdll!RtlpFindEntry. Then it moves the value to ECX. Later, EAX = ECX - 8. Since EAX is -8, so ECX is 0, and thereby EAX is 0 and ntdll!RtlpFindEntry might return NULL for some reason. However, the code seems to assume ntdll!RtlpFindEntry will return some valid address.





Saturday, January 10, 2009

Avoid using name for well-known sid

Last week, I received the escalation that WTM could not be installed on German OS. In the log file, it seemed that SetEntriesInAcl returned the error code 534. As I checked the error code in Winerror.h. It means ERROR_ARITHMETIC_OVERFLOW -- Arithmetic result exceeded 32 bits. Then I looked at the code,

EXPLICIT_ACCESS ea;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = dwAccessRights;
ea.grfAccessMode = AccessMode;
ea.grfInheritance= dwInheritance;

ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TrusteeType;
ea.Trustee.ptstrName = L"EVERYONE";
// Create a new ACL that merges the new ACE into the existing DACL.
PACL pOldDACL = NULL, pNewDACL = NULL;

DWORD dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);

So far, the error code did not make any sense to me. Since the code just tried to add one entry to ACL, and the error code indicated arithmetic overflow. However, one thing caught my attention is the code hard-coded "Everyone" as trustee name. Then I tried to find "Everyone" group on German OS. It turned out that the group could not be found. I knew the code tried to set some permissions on a folder for everyone group. Unfortunately, German OS does not recognize "Everyone". So instead of using "Everyone", I used CreateWellKnownSid passing WinWordSid, which is a predefined well-known sid type for everyone group. The above code would be changed to

EXPLICIT_ACCESS ea;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));

ea.grfAccessPermissions = dwAccessRights;

ea.grfAccessMode = AccessMode;
ea.grfInheritance= dwInheritance;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TrusteeType;

ea.Trustee.ptstrName = pEveryoneSid;

...

With that change, WTM is able to be installed on German OS.