qiling
qiling copied to clipboard
[WIP] Basic C++ support for windows
This PR is based on #917. Complete that one first.
#377 mentions that a simple hello world from C++ on windows, causes a crash.
Demo Code + Crash
HelloWorld.Cpp build with vs2019 for x86 (32 bit)
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
}
Invocation using qiling before applying this PR (dev branch).
~/workspace/qiling$ ./qltool run -f examples/HelloWorldCpp.exe --rootfs examples/rootfs/x86_windows/
[=] Initiate stack address at 0xfffdd000
[=] Loading examples/HelloWorldCpp.exe to 0x400000
[=] PE entry point at 0x411023
[=] TEB addr is 0x6000
[=] PEB addr is 0x6044
[=] Loading examples/rootfs/x86_windows/Windows/System32/ntdll.dll ...
[!] Warnings while loading examples/rootfs/x86_windows/Windows/System32/ntdll.dll:
[!] - SizeOfHeaders is smaller than AddressOfEntryPoint: this file cannot run under Windows 8.
[!] - AddressOfEntryPoint lies outside the sections' boundaries. AddressOfEntryPoint: 0x0
[=] Done with loading examples/rootfs/x86_windows/Windows/System32/ntdll.dll
[=] Loading examples/rootfs/x86_windows/Windows/System32/kernel32.dll ...
[=] Done with loading examples/rootfs/x86_windows/Windows/System32/kernel32.dll
[=] Loading examples/rootfs/x86_windows/Windows/System32/msvcp140d.dll ...
[=] Done with loading examples/rootfs/x86_windows/Windows/System32/msvcp140d.dll
[=] Loading examples/rootfs/x86_windows/Windows/System32/vcruntime140d.dll ...
[=] Done with loading examples/rootfs/x86_windows/Windows/System32/vcruntime140d.dll
[=] Loading examples/rootfs/x86_windows/Windows/System32/ucrtbased.dll ...
[=] Done with loading examples/rootfs/x86_windows/Windows/System32/ucrtbased.dll
[=] GetSystemTimeAsFileTime(lpSystemTimeAsFileTime = 0xffffcfd4)
[=] GetCurrentThreadId() = 0x0
[=] GetCurrentProcessId() = 0x7cc
[=] QueryPerformanceCounter(lpPerformanceCount = 0xffffcfcc) = 0x0
[=] IsProcessorFeaturePresent(ProcessorFeature = 0xa) = 0x1
[=] _initterm_e(pfbegin = 0x41930c, pfend = 0x419618) = 0x0
[=] _initterm(pfbegin = 0x419000, pfend = 0x419208)
[=] _get_initial_narrow_environment() = 0x0
[=] __p___argv() = 0x5000643
[=] __p___argc() = 0x5000647
[=] strlen(str = "Hello World!\n") = 0xd
[x] CPU Context:
[x] ah : 0x99
[x] al : 0x88
[x] ch : 0x0
[x] cl : 0x0
[x] dh : 0x99
[x] dl : 0x88
[x] bh : 0x0
[x] bl : 0x0
[x] ax : 0x9988
[x] cx : 0x0
[x] dx : 0x9988
[x] bx : 0x0
[x] sp : 0xcd20
[x] bp : 0xce94
[x] si : 0x0
[x] di : 0xce84
[x] ip : 0x18b1
[x] eax : 0x100a9988
[x] ecx : 0x0
[x] edx : 0x100a9988
[x] ebx : 0x0
[x] esp : 0xffffcd20
[x] ebp : 0xffffce94
[x] esi : 0x0
[x] edi : 0xffffce84
[x] eip : 0x4118b1
[x] cr0 : 0x11
[x] cr1 : 0x0
[x] cr2 : 0x0
[x] cr3 : 0x0
[x] cr4 : 0x0
[x] cr5 : 0x0
[x] cr6 : 0x0
[x] cr7 : 0x0
[x] cr8 : 0x0
[x] cr9 : 0x0
[x] cr10 : 0x0
[x] cr11 : 0x0
[x] cr12 : 0x0
[x] cr13 : 0x0
[x] cr14 : 0x0
[x] cr15 : 0x0
[x] st0 : 0x0
[x] st1 : 0x0
[x] st2 : 0x0
[x] st3 : 0x0
[x] st4 : 0x0
[x] st5 : 0x0
[x] st6 : 0x0
[x] st7 : 0x0
[x] ef : 0x44
[x] cs : 0x1b
[x] ss : 0x28
[x] ds : 0x28
[x] es : 0x28
[x] fs : 0x73
[x] gs : 0x78
[x] Hexdump:
[x] 0351048bf48bcaff
[x] Disassembly:
[=] 004118b1 [[PE] + 0x0118b1] 0351048bf48bcaff15bcd041003bf4e8c0f9ffff8985acfeffff8995b0feffff83bdb0feffff007c797f0983bdacfeffff00766e8b45088b088b55080351048badd edx, dword ptr [ecx + 4]
> mov esi, esp
> mov ecx, edx
> call dword ptr [0x41d0bc]
> cmp esi, esp
> call 0x411285
> mov dword ptr [ebp - 0x154], eax
> mov dword ptr [ebp - 0x150], edx
> cmp dword ptr [ebp - 0x150], 0
> jl 0x411953
> jg 0x4118e5
> cmp dword ptr [ebp - 0x154], 0
> jbe 0x411953
> mov eax, dword ptr [ebp + 8]
> mov ecx, dword ptr [eax]
> mov edx, dword ptr [ebp + 8]
> add edx, dword ptr [ecx + 4]
[x] PC = 0x004118b1 (examples/HelloWorldCpp.exe + 0x118b1)
[=] Memory map:
[=] Start End Perm Label Image
[=] 00006000 - 0000c000 rwx [FS/GS]
[=] 00030000 - 00031000 rwx [GDT]
[=] 00400000 - 00422000 rwx [PE] examples/HelloWorldCpp.exe
[=] 05000000 - 05001000 rwx [heap]
[=] 06000000 - 0c000000 rwx [FS/GS]
[=] 10000000 - 100b3000 rwx msvcp140d.dll examples/rootfs/x86_windows/Windows/System32/msvcp140d.dll
[=] 100c0000 - 100de000 rwx vcruntime140d.dll examples/rootfs/x86_windows/Windows/System32/vcruntime140d.dll
[=] 100e0000 - 10256000 rwx ucrtbased.dll examples/rootfs/x86_windows/Windows/System32/ucrtbased.dll
[=] 4b280000 - 4b423000 rwx ntdll.dll examples/rootfs/x86_windows/Windows/System32/ntdll.dll
[=] 6b800000 - 6b8e5000 rwx kernel32.dll examples/rootfs/x86_windows/Windows/System32/kernel32.dll
[=] fffdd000 - ffffe000 rwx [stack]
Traceback (most recent call last):
File "./qltool", line 256, in <module>
ql.run(timeout=options.timeout)
File "/home/user/workspace/qiling/qiling/core.py", line 728, in run
self.os.run()
File "/home/user/workspace/qiling/qiling/os/windows/windows.py", line 179, in run
self.ql.emu_start(self.ql.loader.entry_point, self.exit_point, self.ql.timeout, self.ql.count)
File "/home/user/workspace/qiling/qiling/core.py", line 875, in emu_start
self.uc.emu_start(begin, end, timeout, count)
File "/usr/local/lib/python3.7/dist-packages/unicorn/unicorn.py", line 341, in emu_start
raise UcError(status)
unicorn.unicorn.UcError: Invalid memory read (UC_ERR_READ_UNMAPPED)
The reason for this crash is, that std::cout is not initialized. std::cout is usually initialized by the dll entry point of msvcp140d.dll.
There are two ways of fixing this:
- Try to reimplement all std api calls in qiling, effectively replacing half of the STL.
- Try to run the existing STL implementation inside of msvcp140d.dll and hope that the implementation calls primitives that we've already wrapped/replaced ("e.g. printf")
This PR focuses on the 2nd approach. The supplied changes patch some windows API functions so that the DllMain of msvcp140d.dll runs through and does not longer crash. This will intialize std::cout and prevent the crash in main().
In the current state of the PR "hello world" does not appear on the console yet. However, the sample application does no longer crash and instead terminates successfully after running main with exit code 0 :partying_face: .
New output
generated by qiling after applying this PR~/workspace/qiling$ ./qltool run -f examples/HelloWorldCpp.exe --rootfs examples/rootfs/x86_windows/
< huge output of DllMain omitted >
[=] _get_initial_narrow_environment() = 0x5007ad1
[=] __p___argv() = 0x5007af4
[=] __p___argc() = 0x5007af8
[=] strlen(str = "Hello World!\n") = 0xd
[!] api ?width@ios_base@std@@QBE_JXZ is not implemented
[!] api ?rdbuf@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEPAV?$basic_streambuf@DU?$char_traits@D@std@@@2@XZ is not implemented
[!] api ?good@ios_base@std@@QBE_NXZ is not implemented
[!] api ?rdstate@ios_base@std@@QBEHXZ is not implemented
[!] api ?tie@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEPAV?$basic_ostream@DU?$char_traits@D@std@@@2@XZ is not implemented
[!] api ?flags@ios_base@std@@QBEHXZ is not implemented
[!] api ?rdbuf@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEPAV?$basic_streambuf@DU?$char_traits@D@std@@@2@XZ is not implemented
[!] api ?sputn@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QAE_JPBD_J@Z is not implemented
[!] api ?_Pnavail@?$basic_streambuf@DU?$char_traits@D@std@@@std@@IBE_JXZ is not implemented
[!] api ?width@ios_base@std@@QAE_J_J@Z is not implemented
[!] api ?setstate@?$basic_ios@DU?$char_traits@D@std@@@std@@QAEXH_N@Z is not implemented
[!] api ?rdstate@ios_base@std@@QBEHXZ is not implemented
[!] api ?clear@?$basic_ios@DU?$char_traits@D@std@@@std@@QAEXH_N@Z is not implemented
[!] api ?clear@ios_base@std@@QAEXH_N@Z is not implemented
[!] api ?uncaught_exception@std@@YA_NXZ is not implemented
[!] api __uncaught_exception is not implemented
[=] GetLastError() = 0x0
[=] GetProcAddress(hModule = 0x6b800000, lpProcName = "FlsGetValue") = 0x6b81e770
[=] FlsGetValue(dwFlsIndex = 0x3) = 0x102fa248
[=] SetLastError(dwErrCode = 0)
[!] api ?_Osfx@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEXXZ is not implemented
[!] api ?good@ios_base@std@@QBE_NXZ is not implemented
[!] api ?rdstate@ios_base@std@@QBEHXZ is not implemented
[!] api ?rdbuf@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEPAV?$basic_streambuf@DU?$char_traits@D@std@@@2@XZ is not implemented
[=] GetModuleHandleW(lpModuleName = 0) = 0x400000
[=] exit(status = 0)
Note that uncaught_exception is a getter. There is no exception happening.
Next Steps:
- Getting the output of
std::coutto the console. - Try more complex c++ programs
Checklist
Which kind of PR do you create?
- [x] This PR only contains minor fixes.
- [ ] This PR contains major feature update.
- [ ] This PR introduces a new function/api for Qiling Framework.
Coding convention?
- [x] The new code conforms to Qiling Framework naming convention.
- [x] The imports are arranged properly.
- [x] Essential comments are added.
- [x] The reference of the new code is pointed out.
Extra tests?
- [ ] No extra tests are needed for this PR.
- [ ] I have added enough tests for this PR.
- [x] Tests will be added after some discussion and review.
Changelog?
- [ ] This PR doesn't need to update Changelog.
- [x] Changelog will be updated after some proper review.
- [ ] Changelog has been updated in my PR.
Target branch?
- [x] The target branch is dev branch.
One last thing
- [x] I have read the contribution guide
Nice work, we needed this long ago
@wtdcode by removing old_dev you might have accidentally closed this pr... Can this be easily re targeted to dev?
@wtdcode by removing old_dev you might have accidentally closed this pr... Can this be easily re targeted to dev?
Github doesn't allow to change base at this time... Need @t-moe to re-open another one. Sorry for any inconvenience.
i changed the base to dev. @t-moe can you please resolv the conflict ?