[2020]CPU仿真的一些记录: GS寄存器处理 huoji CPU仿真,GS寄存器,unicorn-engine 2020-12-13 2299 次浏览 0 次点赞 ## 前言 最近在用unicorn-engine作CPU仿真,遇到的坑比较多.所以写个笔记以免遗忘 在exe run的之前 会调用getcurrentthreadid getcurrentthreadid 在kernelbase.dll里面代码如下: ![CPU仿真](https://key08.com/usr/uploads/2020/12/3997742032.png) 读gs寄存器 + 0x30 -读出TEB 然后再读teb + 0x48 -teb->ClientId.UniqueThread 网上唯一的基于UC的CPU仿真工具是hzqst的PE模拟器 ## 存在的问题 https://github.com/hzqst/unicorn_pe/tree/master/unicorn_pe 他的代码有问题直接把gs_base = teb_base了 ![CPU仿真](https://key08.com/usr/uploads/2020/12/4001037418.png) 这就造成这一段必崩 ## 科学解决 首先是结构(暂时只做了x64的,32的还要单独模拟,特别痛苦) ```cpp /* x64的teb_64 32位的没做 */ struct _ACTIVATION_CONTEXT_STACK { struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; //0x0 struct _LIST_ENTRY FrameListCache; //0x8 ULONG Flags; //0x18 ULONG NextCookieSequenceNumber; //0x1c ULONG StackId; //0x20 }; struct _GDI_TEB_BATCH { ULONG Offset : 31; //0x0 ULONG HasRenderingCommand : 1; //0x0 ULONGLONG HDC; //0x8 ULONG Buffer[310]; //0x10 }; struct _CLIENT_ID { DWORD64 UniqueProcess; //0x0 DWORD64 UniqueThread; //0x8 }; static_assert(sizeof(_CLIENT_ID) == 0x10, "_CLIENT_ID Size check"); static_assert(sizeof(_NT_TIB) == 0x38, "_NT_TIB Size check"); typedef struct X64TEB { struct _NT_TIB NtTib; //0x0 VOID* EnvironmentPointer; //0x38 struct _CLIENT_ID ClientId; //0x40 VOID* ActiveRpcHandle; //0x50 VOID* ThreadLocalStoragePointer; //0x58 struct _PEB* ProcessEnvironmentBlock; //0x60 ULONG LastErrorValue; //0x68 ULONG CountOfOwnedCriticalSections; //0x6c VOID* CsrClientThread; //0x70 VOID* Win32ThreadInfo; //0x78 ULONG User32Reserved[26]; //0x80 ULONG UserReserved[5]; //0xe8 VOID* WOW32Reserved; //0x100 ULONG CurrentLocale; //0x108 ULONG FpSoftwareStatusRegister; //0x10c VOID* ReservedForDebuggerInstrumentation[16]; //0x110 VOID* SystemReserved1[30]; //0x190 CHAR PlaceholderCompatibilityMode; //0x280 UCHAR PlaceholderHydrationAlwaysExplicit; //0x281 CHAR PlaceholderReserved[10]; //0x282 ULONG ProxiedProcessId; //0x28c struct _ACTIVATION_CONTEXT_STACK _ActivationStack; //0x290 UCHAR WorkingOnBehalfTicket[8]; //0x2b8 LONG ExceptionCode; //0x2c0 UCHAR Padding0[4]; //0x2c4 struct _ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; //0x2c8 ULONGLONG InstrumentationCallbackSp; //0x2d0 ULONGLONG InstrumentationCallbackPreviousPc; //0x2d8 ULONGLONG InstrumentationCallbackPreviousSp; //0x2e0 ULONG TxFsContext; //0x2e8 UCHAR InstrumentationCallbackDisabled; //0x2ec UCHAR UnalignedLoadStoreExceptions; //0x2ed UCHAR Padding1[2]; //0x2ee struct _GDI_TEB_BATCH GdiTebBatch; //0x2f0 struct _CLIENT_ID RealClientId; //0x7d8 VOID* GdiCachedProcessHandle; //0x7e8 ULONG GdiClientPID; //0x7f0 ULONG GdiClientTID; //0x7f4 VOID* GdiThreadLocalInfo; //0x7f8 ULONGLONG Win32ClientInfo[62]; //0x800 VOID* glDispatchTable[233]; //0x9f0 ULONGLONG glReserved1[29]; //0x1138 VOID* glReserved2; //0x1220 VOID* glSectionInfo; //0x1228 VOID* glSection; //0x1230 VOID* glTable; //0x1238 VOID* glCurrentRC; //0x1240 VOID* glContext; //0x1248 ULONG LastStatusValue; //0x1250 UCHAR Padding2[4]; //0x1254 struct _UNICODE_STRING StaticUnicodeString; //0x1258 WCHAR StaticUnicodeBuffer[261]; //0x1268 UCHAR Padding3[6]; //0x1472 VOID* DeallocationStack; //0x1478 VOID* TlsSlots[64]; //0x1480 struct _LIST_ENTRY TlsLinks; //0x1680 VOID* Vdm; //0x1690 VOID* ReservedForNtRpc; //0x1698 VOID* DbgSsReserved[2]; //0x16a0 ULONG HardErrorMode; //0x16b0 UCHAR Padding4[4]; //0x16b4 VOID* Instrumentation[11]; //0x16b8 struct _GUID ActivityId; //0x1710 VOID* SubProcessTag; //0x1720 VOID* PerflibData; //0x1728 VOID* EtwTraceData; //0x1730 VOID* WinSockData; //0x1738 ULONG GdiBatchCount; //0x1740 union { struct _PROCESSOR_NUMBER CurrentIdealProcessor; //0x1744 ULONG IdealProcessorValue; //0x1744 struct { UCHAR ReservedPad0; //0x1744 UCHAR ReservedPad1; //0x1745 UCHAR ReservedPad2; //0x1746 UCHAR IdealProcessor; //0x1747 }; }; ULONG GuaranteedStackBytes; //0x1748 UCHAR Padding5[4]; //0x174c VOID* ReservedForPerf; //0x1750 VOID* ReservedForOle; //0x1758 ULONG WaitingOnLoaderLock; //0x1760 UCHAR Padding6[4]; //0x1764 VOID* SavedPriorityState; //0x1768 ULONGLONG ReservedForCodeCoverage; //0x1770 VOID* ThreadPoolData; //0x1778 VOID** TlsExpansionSlots; //0x1780 VOID* DeallocationBStore; //0x1788 VOID* BStoreLimit; //0x1790 ULONG MuiGeneration; //0x1798 ULONG IsImpersonating; //0x179c VOID* NlsCache; //0x17a0 VOID* pShimData; //0x17a8 ULONG HeapData; //0x17b0 UCHAR Padding7[4]; //0x17b4 VOID* CurrentTransactionHandle; //0x17b8 struct _TEB_ACTIVE_FRAME* ActiveFrame; //0x17c0 VOID* FlsData; //0x17c8 VOID* PreferredLanguages; //0x17d0 VOID* UserPrefLanguages; //0x17d8 VOID* MergedPrefLanguages; //0x17e0 ULONG MuiImpersonation; //0x17e8 union { volatile USHORT CrossTebFlags; //0x17ec USHORT SpareCrossTebBits : 16; //0x17ec }; union { USHORT SameTebFlags; //0x17ee struct { USHORT SafeThunkCall : 1; //0x17ee USHORT InDebugPrint : 1; //0x17ee USHORT HasFiberData : 1; //0x17ee USHORT SkipThreadAttach : 1; //0x17ee USHORT WerInShipAssertCode : 1; //0x17ee USHORT RanProcessInit : 1; //0x17ee USHORT ClonedThread : 1; //0x17ee USHORT SuppressDebugMsg : 1; //0x17ee USHORT DisableUserStackWalk : 1; //0x17ee USHORT RtlExceptionAttached : 1; //0x17ee USHORT InitialThread : 1; //0x17ee USHORT SessionAware : 1; //0x17ee USHORT LoadOwner : 1; //0x17ee USHORT LoaderWorker : 1; //0x17ee USHORT SkipLoaderInit : 1; //0x17ee USHORT SpareSameTebBits : 1; //0x17ee }; }; VOID* TxnScopeEnterCallback; //0x17f0 VOID* TxnScopeExitCallback; //0x17f8 VOID* TxnScopeContext; //0x1800 ULONG LockCount; //0x1808 LONG WowTebOffset; //0x180c VOID* ResourceRetValue; //0x1810 VOID* ReservedForWdf; //0x1818 ULONGLONG ReservedForCrt; //0x1820 struct _GUID EffectiveContainerId; //0x1828 }; static_assert(sizeof(X64TEB) == 0x1838, "TEB Size check"); ``` 然后模拟gs寄存器结构 ```cpp struct struct_gs_base { char unk[0x30]; //0x0 uint64_t teb; //0x30 }; ``` 然后设置msr_gs_base即可 完整代码如下: ```cpp /* 设置PEB */ PEB peb = { 0 }; m_PebBase = 0x90000; m_PebEnd = m_PebBase + AlignSize(sizeof(PEB), PAGE_SIZE); /* 设置TEB */ m_TebBase = 0x80000; m_TebEnd = m_TebBase + AlignSize(sizeof(X64TEB), PAGE_SIZE); uint64_t teb_alloc_size = AlignSize(sizeof(X64TEB), PAGE_SIZE); X64TEB teb = { 0 }; teb.ClientId.UniqueProcess = 0x1337; teb.ClientId.UniqueThread = 0x1337; teb.ProcessEnvironmentBlock = (PPEB)m_PebBase; /* 设置GS */ struct_gs_base gs_base = {0}; gs_base.teb = m_TebBase; uint64_t gs_alloc_size = AlignSize(sizeof(struct_gs_base), PAGE_SIZE); //__debugbreak(); /* 映射 */ //peb uc_mem_map(g_global->uc_engine, m_PebBase, m_PebEnd - m_PebBase, UC_PROT_READ); uc_mem_write(g_global->uc_engine, m_PebBase, &peb, sizeof(PEB)); //teb uc_mem_map(g_global->uc_engine, m_TebBase, m_TebEnd - m_TebBase, UC_PROT_READ); uc_mem_write(g_global->uc_engine, m_TebBase, &teb, sizeof(X64TEB)); //gs uc_mem_map(g_global->uc_engine, 0x7efdd000, gs_alloc_size, UC_PROT_READ); uc_mem_write(g_global->uc_engine, 0x7efdd000, &gs_base, sizeof(struct_gs_base)); /* //测试 uint64_t read; auto error = uc_mem_read(g_global->uc_engine, g_global->gs_base, &read,0x8); printf("error: %d read: %08X \n", error, read); */ uc_x86_msr msr; msr.rid = (uint32_t)Msr::kIa32GsBase; msr.value = m_gs_base; uc_reg_write(g_global->uc_engine, UC_X86_REG_MSR, &msr); ``` 注意新手容易犯的错: > gs寄存器不能直接uc_reg_write带个UC_X86_REG_GS,这样做的都是菜鸡没了解过操作系统就直接上手的建议百度gdt、kpcr、gs寄存器了解一下再上手。 > uc提供了一个UC_X86_REG_GS_BASE参数但是用不了发挥不了作用就很奇怪,还是按照老方法写msr ## 效果: ![](https://key08.com/usr/uploads/2020/12/2988470711.png) ## 参考资料 https://github.com/cseagle/sk3wldbg/issues/18 本文由 huoji 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。 点赞 0
这部分感觉可以去参考qiling(python的基于unicorn的模拟器,是怎么处理这部分的)
麒麟目前没有c++源码 他们的py实现是直接填充gs寄存器 但是具体怎么做、如何做都没有说明