CpuDbg 发表于 2022-10-5 16:53:08

获取线程中LastError最近的一次错误

一般写程序的时候可以通过 GetLastError 来获取错误信息.
如果是想读取别人程序中的线程错误, 可以通过TEB来读取.
下面给出 32 和 64 程序中 LastError 的偏移位置.

// 下面这个是 win10 x64 下,32位程序

0:000> dt _teb
ntdll_771c0000!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle: Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
   +0x034 LastErrorValue   : Uint4B   // <----------------------------------------------------32位程序 LastError 偏移是0x34
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread: Ptr32 Void
   +0x040 Win32ThreadInfo: Ptr32 Void
   +0x044 User32Reserved   : Uint4B
   +0x0ac UserReserved   : Uint4B
   +0x0c0 WOW32Reserved    : Ptr32 Void
   +0x0c4 CurrentLocale    : Uint4B
   +0x0c8 FpSoftwareStatusRegister : Uint4B
   +0x0cc ReservedForDebuggerInstrumentation : Ptr32 Void
   +0x10c SystemReserved1: Ptr32 Void
   +0x174 PlaceholderCompatibilityMode : Char
   +0x175 PlaceholderHydrationAlwaysExplicit : UChar
   +0x176 PlaceholderReserved : Char
   +0x180 ProxiedProcessId : Uint4B
   +0x184 _ActivationStack : _ACTIVATION_CONTEXT_STACK
   +0x19c WorkingOnBehalfTicket : UChar
   +0x1a4 ExceptionCode    : Int4B
   +0x1a8 ActivationContextStackPointer : Ptr32 _ACTIVATION_CONTEXT_STACK
   +0x1ac InstrumentationCallbackSp : Uint4B
   +0x1b0 InstrumentationCallbackPreviousPc : Uint4B
   +0x1b4 InstrumentationCallbackPreviousSp : Uint4B
   +0x1b8 InstrumentationCallbackDisabled : UChar
   +0x1b9 SpareBytes       : UChar
   +0x1d0 TxFsContext      : Uint4B
   +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
   +0x6b4 RealClientId   : _CLIENT_ID
   +0x6bc GdiCachedProcessHandle : Ptr32 Void
   +0x6c0 GdiClientPID   : Uint4B
   +0x6c4 GdiClientTID   : Uint4B
   +0x6c8 GdiThreadLocalInfo : Ptr32 Void
   +0x6cc Win32ClientInfo: Uint4B
   +0x7c4 glDispatchTable: Ptr32 Void
   +0xb68 glReserved1      : Uint4B
   +0xbdc glReserved2      : Ptr32 Void
   +0xbe0 glSectionInfo    : Ptr32 Void
   +0xbe4 glSection      : Ptr32 Void
   +0xbe8 glTable          : Ptr32 Void
   +0xbec glCurrentRC      : Ptr32 Void
   +0xbf0 glContext      : Ptr32 Void
   +0xbf4 LastStatusValue: Uint4B
   +0xbf8 StaticUnicodeString : _UNICODE_STRING
   +0xc00 StaticUnicodeBuffer : Wchar
   +0xe0c DeallocationStack : Ptr32 Void
   +0xe10 TlsSlots         : Ptr32 Void
   +0xf10 TlsLinks         : _LIST_ENTRY
   +0xf18 Vdm            : Ptr32 Void
   +0xf1c ReservedForNtRpc : Ptr32 Void
   +0xf20 DbgSsReserved    : Ptr32 Void
   +0xf28 HardErrorMode    : Uint4B
   +0xf2c Instrumentation: Ptr32 Void
   +0xf50 ActivityId       : _GUID
   +0xf60 SubProcessTag    : Ptr32 Void
   +0xf64 PerflibData      : Ptr32 Void
   +0xf68 EtwTraceData   : Ptr32 Void
   +0xf6c WinSockData      : Ptr32 Void
   +0xf70 GdiBatchCount    : Uint4B
   +0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
   +0xf74 IdealProcessorValue : Uint4B
   +0xf74 ReservedPad0   : UChar
   +0xf75 ReservedPad1   : UChar
   +0xf76 ReservedPad2   : UChar
   +0xf77 IdealProcessor   : UChar
   +0xf78 GuaranteedStackBytes : Uint4B
   +0xf7c ReservedForPerf: Ptr32 Void
   +0xf80 ReservedForOle   : Ptr32 Void
   +0xf84 WaitingOnLoaderLock : Uint4B
   +0xf88 SavedPriorityState : Ptr32 Void
   +0xf8c ReservedForCodeCoverage : Uint4B
   +0xf90 ThreadPoolData   : Ptr32 Void
   +0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
   +0xf98 MuiGeneration    : Uint4B
   +0xf9c IsImpersonating: Uint4B
   +0xfa0 NlsCache         : Ptr32 Void
   +0xfa4 pShimData      : Ptr32 Void
   +0xfa8 HeapData         : Uint4B
   +0xfac CurrentTransactionHandle : Ptr32 Void
   +0xfb0 ActiveFrame      : Ptr32 _TEB_ACTIVE_FRAME
   +0xfb4 FlsData          : Ptr32 Void
   +0xfb8 PreferredLanguages : Ptr32 Void
   +0xfbc UserPrefLanguages : Ptr32 Void
   +0xfc0 MergedPrefLanguages : Ptr32 Void
   +0xfc4 MuiImpersonation : Uint4B
   +0xfc8 CrossTebFlags    : Uint2B
   +0xfc8 SpareCrossTebBits : Pos 0, 16 Bits
   +0xfca SameTebFlags   : Uint2B
   +0xfca SafeThunkCall    : Pos 0, 1 Bit
   +0xfca InDebugPrint   : Pos 1, 1 Bit
   +0xfca HasFiberData   : Pos 2, 1 Bit
   +0xfca SkipThreadAttach : Pos 3, 1 Bit
   +0xfca WerInShipAssertCode : Pos 4, 1 Bit
   +0xfca RanProcessInit   : Pos 5, 1 Bit
   +0xfca ClonedThread   : Pos 6, 1 Bit
   +0xfca SuppressDebugMsg : Pos 7, 1 Bit
   +0xfca DisableUserStackWalk : Pos 8, 1 Bit
   +0xfca RtlExceptionAttached : Pos 9, 1 Bit
   +0xfca InitialThread    : Pos 10, 1 Bit
   +0xfca SessionAware   : Pos 11, 1 Bit
   +0xfca LoadOwner      : Pos 12, 1 Bit
   +0xfca LoaderWorker   : Pos 13, 1 Bit
   +0xfca SkipLoaderInit   : Pos 14, 1 Bit
   +0xfca SpareSameTebBits : Pos 15, 1 Bit
   +0xfcc TxnScopeEnterCallback : Ptr32 Void
   +0xfd0 TxnScopeExitCallback : Ptr32 Void
   +0xfd4 TxnScopeContext: Ptr32 Void
   +0xfd8 LockCount      : Uint4B
   +0xfdc WowTebOffset   : Int4B
   +0xfe0 ResourceRetValue : Ptr32 Void
   +0xfe4 ReservedForWdf   : Ptr32 Void
   +0xfe8 ReservedForCrt   : Uint8B
   +0xff0 EffectiveContainerId : _GUID




// 下面这个是 win10 x64 下,64位程序

0:000> dt _teb
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x038 EnvironmentPointer : Ptr64 Void
   +0x040 ClientId         : _CLIENT_ID
   +0x050 ActiveRpcHandle: Ptr64 Void
   +0x058 ThreadLocalStoragePointer : Ptr64 Void
   +0x060 ProcessEnvironmentBlock : Ptr64 _PEB
   +0x068 LastErrorValue   : Uint4B      // <----------------------------------------------------64位程序 LastError 偏移是0x68
   +0x06c CountOfOwnedCriticalSections : Uint4B
   +0x070 CsrClientThread: Ptr64 Void
   +0x078 Win32ThreadInfo: Ptr64 Void
   +0x080 User32Reserved   : Uint4B
   +0x0e8 UserReserved   : Uint4B
   +0x100 WOW32Reserved    : Ptr64 Void
   +0x108 CurrentLocale    : Uint4B
   +0x10c FpSoftwareStatusRegister : Uint4B
   +0x110 ReservedForDebuggerInstrumentation : Ptr64 Void
   +0x190 SystemReserved1: Ptr64 Void
   +0x280 PlaceholderCompatibilityMode : Char
   +0x281 PlaceholderHydrationAlwaysExplicit : UChar
   +0x282 PlaceholderReserved : Char
   +0x28c ProxiedProcessId : Uint4B
   +0x290 _ActivationStack : _ACTIVATION_CONTEXT_STACK
   +0x2b8 WorkingOnBehalfTicket : UChar
   +0x2c0 ExceptionCode    : Int4B
   +0x2c4 Padding0         : UChar
   +0x2c8 ActivationContextStackPointer : Ptr64 _ACTIVATION_CONTEXT_STACK
   +0x2d0 InstrumentationCallbackSp : Uint8B
   +0x2d8 InstrumentationCallbackPreviousPc : Uint8B
   +0x2e0 InstrumentationCallbackPreviousSp : Uint8B
   +0x2e8 TxFsContext      : Uint4B
   +0x2ec InstrumentationCallbackDisabled : UChar
   +0x2ed UnalignedLoadStoreExceptions : UChar
   +0x2ee Padding1         : UChar
   +0x2f0 GdiTebBatch      : _GDI_TEB_BATCH
   +0x7d8 RealClientId   : _CLIENT_ID
   +0x7e8 GdiCachedProcessHandle : Ptr64 Void
   +0x7f0 GdiClientPID   : Uint4B
   +0x7f4 GdiClientTID   : Uint4B
   +0x7f8 GdiThreadLocalInfo : Ptr64 Void
   +0x800 Win32ClientInfo: Uint8B
   +0x9f0 glDispatchTable: Ptr64 Void
   +0x1138 glReserved1      : Uint8B
   +0x1220 glReserved2      : Ptr64 Void
   +0x1228 glSectionInfo    : Ptr64 Void
   +0x1230 glSection      : Ptr64 Void
   +0x1238 glTable          : Ptr64 Void
   +0x1240 glCurrentRC      : Ptr64 Void
   +0x1248 glContext      : Ptr64 Void
   +0x1250 LastStatusValue: Uint4B
   +0x1254 Padding2         : UChar
   +0x1258 StaticUnicodeString : _UNICODE_STRING
   +0x1268 StaticUnicodeBuffer : Wchar
   +0x1472 Padding3         : UChar
   +0x1478 DeallocationStack : Ptr64 Void
   +0x1480 TlsSlots         : Ptr64 Void
   +0x1680 TlsLinks         : _LIST_ENTRY
   +0x1690 Vdm            : Ptr64 Void
   +0x1698 ReservedForNtRpc : Ptr64 Void
   +0x16a0 DbgSsReserved    : Ptr64 Void
   +0x16b0 HardErrorMode    : Uint4B
   +0x16b4 Padding4         : UChar
   +0x16b8 Instrumentation: Ptr64 Void
   +0x1710 ActivityId       : _GUID
   +0x1720 SubProcessTag    : Ptr64 Void
   +0x1728 PerflibData      : Ptr64 Void
   +0x1730 EtwTraceData   : Ptr64 Void
   +0x1738 WinSockData      : Ptr64 Void
   +0x1740 GdiBatchCount    : Uint4B
   +0x1744 CurrentIdealProcessor : _PROCESSOR_NUMBER
   +0x1744 IdealProcessorValue : Uint4B
   +0x1744 ReservedPad0   : UChar
   +0x1745 ReservedPad1   : UChar
   +0x1746 ReservedPad2   : UChar
   +0x1747 IdealProcessor   : UChar
   +0x1748 GuaranteedStackBytes : Uint4B
   +0x174c Padding5         : UChar
   +0x1750 ReservedForPerf: Ptr64 Void
   +0x1758 ReservedForOle   : Ptr64 Void
   +0x1760 WaitingOnLoaderLock : Uint4B
   +0x1764 Padding6         : UChar
   +0x1768 SavedPriorityState : Ptr64 Void
   +0x1770 ReservedForCodeCoverage : Uint8B
   +0x1778 ThreadPoolData   : Ptr64 Void
   +0x1780 TlsExpansionSlots : Ptr64 Ptr64 Void
   +0x1788 DeallocationBStore : Ptr64 Void
   +0x1790 BStoreLimit      : Ptr64 Void
   +0x1798 MuiGeneration    : Uint4B
   +0x179c IsImpersonating: Uint4B
   +0x17a0 NlsCache         : Ptr64 Void
   +0x17a8 pShimData      : Ptr64 Void
   +0x17b0 HeapData         : Uint4B
   +0x17b4 Padding7         : UChar
   +0x17b8 CurrentTransactionHandle : Ptr64 Void
   +0x17c0 ActiveFrame      : Ptr64 _TEB_ACTIVE_FRAME
   +0x17c8 FlsData          : Ptr64 Void
   +0x17d0 PreferredLanguages : Ptr64 Void
   +0x17d8 UserPrefLanguages : Ptr64 Void
   +0x17e0 MergedPrefLanguages : Ptr64 Void
   +0x17e8 MuiImpersonation : Uint4B
   +0x17ec CrossTebFlags    : Uint2B
   +0x17ec SpareCrossTebBits : Pos 0, 16 Bits
   +0x17ee SameTebFlags   : Uint2B
   +0x17ee SafeThunkCall    : Pos 0, 1 Bit
   +0x17ee InDebugPrint   : Pos 1, 1 Bit
   +0x17ee HasFiberData   : Pos 2, 1 Bit
   +0x17ee SkipThreadAttach : Pos 3, 1 Bit
   +0x17ee WerInShipAssertCode : Pos 4, 1 Bit
   +0x17ee RanProcessInit   : Pos 5, 1 Bit
   +0x17ee ClonedThread   : Pos 6, 1 Bit
   +0x17ee SuppressDebugMsg : Pos 7, 1 Bit
   +0x17ee DisableUserStackWalk : Pos 8, 1 Bit
   +0x17ee RtlExceptionAttached : Pos 9, 1 Bit
   +0x17ee InitialThread    : Pos 10, 1 Bit
   +0x17ee SessionAware   : Pos 11, 1 Bit
   +0x17ee LoadOwner      : Pos 12, 1 Bit
   +0x17ee LoaderWorker   : Pos 13, 1 Bit
   +0x17ee SkipLoaderInit   : Pos 14, 1 Bit
   +0x17ee SpareSameTebBits : Pos 15, 1 Bit
   +0x17f0 TxnScopeEnterCallback : Ptr64 Void
   +0x17f8 TxnScopeExitCallback : Ptr64 Void
   +0x1800 TxnScopeContext: Ptr64 Void
   +0x1808 LockCount      : Uint4B
   +0x180c WowTebOffset   : Int4B
   +0x1810 ResourceRetValue : Ptr64 Void
   +0x1818 ReservedForWdf   : Ptr64 Void
   +0x1820 ReservedForCrt   : Uint8B
   +0x1828 EffectiveContainerId : _GUID


读取LastError代码片段:

      
DWORD dwReturnLength = 0;
      DWORD64 dw64TEB = 0;
      WinThreadGetTEB(hThread, dw64TEB);

      if(dw64TEB == 0)
      {
                LogErrorLine("获取TEB失败!");
                return FALSE;
      }

#ifdef _M_X64
      Readmemory(&dw64LastError, dw64TEB+0x68, sizeof(dw64LastError), MM_RESTORE);
#else
      Readmemory(&dw64LastError, dw64TEB+0x34, sizeof(dw64LastError), MM_RESTORE);
#endif


再获取到 LastError 之后, 可以通过FormatMessage 函数来转换成相应的错误介绍. 其中第三个参数是相应的显示语言,
SDK中默认的例子如下:


LPVOID lpMsgBuf;
FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );


其中第三个参数是用了一个 MAKELANGID 宏, 里面有两个参数.就是选择相应的语言.
代码如下:


LPVOID lpMsgBuf;
      FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                dw64LastError,
//                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),         // 缺省,中文
                MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),      // 英文
                (LPTSTR) &lpMsgBuf,
                0,
                NULL
                );

      string strLastError = (PCHAR)lpMsgBuf;

      LogOutput("最近的错误: %s", lpMsgBuf);

      // FormatMessage 获取的数据尾部带有 "\xA3 \r \n", 因此判断, 如果有数据, 则要移除此尾巴.
      // 英文中没有'\xA3' 只有 \r\n 同样需要处理一下.
      if(strLastError.length() > 0)
      {
                int nPos = strLastError.rfind('\xA3');

                // 如果找不到很有可能是英文
                if(nPos == -1)
                {
                        nPos = strLastError.rfind("\r\n");
                }
                strLastError = strLastError.substr(0, nPos-1);
      }


最终中英文效果如下图:



这样就能在调试器的线程窗口中看到目标所有线程的 LastErrorValue 啦 :)
看了几个调试器, 貌似只有od和x64dbg有显示 lasterror, 其中 x64dbg 和 odx64 只显示 lasterror 的 hex值, 没有显示对应的注释.只有 od1.x 和 od2.x 有显示HEX对应的注释.

但是这样显示的中英文错误提示,和 od1.x的好像并不一样. od1.x的显示如下图:



不知道是因为看习惯了, 还是怎么的, 总感觉 od1.x这样的显示 看着让人感觉非常舒服.
而od1.x的提示应该是用的 SDK 中 Winerror.h 的头文件 里面的.如下图:



如果想要显示和od1.x一样的. 还得专门的处理. 有点头疼~_~
等回头再更新这个问题吧. 尽量保持和od1.x一样.
页: [1]
查看完整版本: 获取线程中LastError最近的一次错误