├── README.md ├── xdebugger.pri ├── LICENSE ├── xwinapi.h ├── xunpacker.h ├── xwinapi.cpp ├── xdebugger.h ├── xunpacker.cpp └── xdebugger.cpp /README.md: -------------------------------------------------------------------------------- 1 | # QDebugger 2 | 3 | Debugger 4 | -------------------------------------------------------------------------------- /xdebugger.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD 2 | DEPENDPATH += $$PWD 3 | 4 | HEADERS += \ 5 | $$PWD/xdebugger.h \ 6 | $$PWD/xwinapi.h \ 7 | $$PWD/xunpacker.h 8 | 9 | SOURCES += \ 10 | $$PWD/xdebugger.cpp \ 11 | $$PWD/xwinapi.cpp \ 12 | $$PWD/xunpacker.cpp 13 | 14 | !contains(XCONFIG, xprocess) { 15 | XCONFIG += xprocess 16 | include($$PWD/../XProcess/xprocess.pri) 17 | } 18 | 19 | !contains(XCONFIG, xpe) { 20 | XCONFIG += xpe 21 | include($$PWD/../Formats/xpe.pri) 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 hors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /xwinapi.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef XWINAPI_H 22 | #define XWINAPI_H 23 | 24 | #include 25 | #include "xdebugger.h" 26 | 27 | class XWinAPI : public XDebugger 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | explicit XWinAPI(QObject *parent=nullptr); 33 | 34 | struct KERNEL32_GETPROCADDRESS 35 | { 36 | quint64 nResult; 37 | quint64 _hModule; 38 | quint64 _lpProcName; 39 | QString sLibrary; 40 | bool bIsOrdinal; 41 | quint64 nOrdinal; 42 | QString sFunction; 43 | }; 44 | 45 | struct KERNEL32_EXITPROCESS 46 | { 47 | quint64 nResult; 48 | quint64 _uExitCode; 49 | }; 50 | 51 | struct USER32_MESSAGEBOX 52 | { 53 | quint64 nResult; 54 | quint64 _hWnd; 55 | quint64 _lpText; 56 | quint64 _lpCaption; 57 | quint64 _uType; 58 | QString sText; 59 | QString sCaption; 60 | bool bIsUnicode; 61 | }; 62 | 63 | struct KERNEL32_VIRTUALALLOC 64 | { 65 | quint64 nResult; 66 | quint64 _lpAddress; 67 | quint64 _dwSize; 68 | quint64 _flAllocationType; 69 | quint64 _flProtect; 70 | }; 71 | 72 | enum PARAMS 73 | { 74 | PARAMS_KERNEL32_GETPROCADDRESS=2, 75 | PARAMS_USER32_MESSAGEBOX=4, 76 | PARAMS_KERNEL32_EXITPROCESS=1, 77 | }; 78 | 79 | enum HANDLE_TYPE 80 | { 81 | HANDLE_TYPE_ENTER=0, 82 | HANDLE_TYPE_LEAVE 83 | }; 84 | 85 | static void handle_Kernel32_GetProcAddress(XDebugger *pDebugger,XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,KERNEL32_GETPROCADDRESS *pData); 86 | static void handle_User32_MessageBox(XDebugger *pDebugger,XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,bool bIsUnicode,USER32_MESSAGEBOX *pData); 87 | static void handle_Kernel32_ExitProcess(XDebugger *pDebugger,XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,KERNEL32_EXITPROCESS *pData); 88 | static void handle_Kernel32_VirtualAlloc(XDebugger *pDebugger,XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,KERNEL32_VIRTUALALLOC *pData); 89 | }; 90 | 91 | #endif // XWINAPI_H 92 | -------------------------------------------------------------------------------- /xunpacker.h: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2021 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef XUNPACKER_H 22 | #define XUNPACKER_H 23 | 24 | #include 25 | #include 26 | #include "xdebugger.h" 27 | #include "xwinapi.h" 28 | 29 | class XUnpacker : public XDebugger 30 | { 31 | Q_OBJECT 32 | 33 | public: 34 | struct IMPORT_BUILD_RECORD 35 | { 36 | qint64 nPatchAddress; 37 | QString sLibrary; 38 | bool bIsOrdinal; 39 | quint64 nOrdinal; 40 | QString sFunction; 41 | quint64 nValue; 42 | }; 43 | 44 | struct RELOC_BUILD_RECORD 45 | { 46 | qint64 nPatchAddress; 47 | quint64 nValue; 48 | }; 49 | 50 | struct DUMP_OPTIONS 51 | { 52 | qint64 nAddressOfEntryPoint; 53 | bool bFixChecksum; 54 | bool bPatchNWError6002; 55 | }; 56 | 57 | enum UNPACK_OPTIONS_ID 58 | { 59 | UNPACK_OPTIONS_ID_UNKNOWN=0, 60 | UNPACK_OPTIONS_ID_FIXCHECKSUM, 61 | UNPACK_OPTIONS_ID_PATCHNW 62 | }; 63 | 64 | enum UNPACK_OPTIONS_VAR_TYPE 65 | { 66 | UNPACK_OPTIONS_VAR_TYPE_UNKNOWN=-1, 67 | UNPACK_OPTIONS_VAR_TYPE_BOOL 68 | }; 69 | 70 | struct UNPACK_OPTIONS_RECORD 71 | { 72 | quint32 nID; 73 | QString sName; 74 | QString sDescription; 75 | UNPACK_OPTIONS_VAR_TYPE varType; 76 | QVariant var; 77 | }; 78 | 79 | explicit XUnpacker(QObject *parent=nullptr); 80 | 81 | bool dumpToFile(QString sFileName,DUMP_OPTIONS *pDumpOptions); 82 | QMap getImportMap(); 83 | QList getRelocsList(); 84 | 85 | QString getResultFileName(); 86 | 87 | bool unpack(QString sFileName,QString sResultFileName,QList *pListUnpackOptions); 88 | 89 | virtual QList getDefaultUnpackOptions(); 90 | QVariant getUnpackOptionValue(quint32 nID); 91 | 92 | protected: 93 | virtual void _clear(); 94 | void addImportBuildRecord(IMPORT_BUILD_RECORD record); 95 | void addRelocBuildRecord(RELOC_BUILD_RECORD record); 96 | 97 | private: 98 | QMap mapImportBuildRecords; 99 | QMap mapRelocBuildRecords; 100 | 101 | QString sResultFileName; 102 | QList listUnpackOptions; 103 | }; 104 | 105 | #endif // XUNPACKER_H 106 | -------------------------------------------------------------------------------- /xwinapi.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "xwinapi.h" 22 | 23 | XWinAPI::XWinAPI(QObject *parent) : XDebugger(parent) 24 | { 25 | 26 | } 27 | 28 | void XWinAPI::handle_Kernel32_GetProcAddress(XDebugger *pDebugger, XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,KERNEL32_GETPROCADDRESS *pData) 29 | { 30 | if(handleType==HANDLE_TYPE_ENTER) 31 | { 32 | *pData={}; 33 | 34 | pData->_hModule=pDebugger->getFunctionParameter(pFunctionInfo,0); 35 | pData->_lpProcName=pDebugger->getFunctionParameter(pFunctionInfo,1); 36 | 37 | pData->sLibrary=pDebugger->getMapDLL()->value(pData->_hModule).sName; 38 | 39 | #ifndef Q_OS_WIN64 40 | if(pData->_lpProcName&0xFFFF0000) 41 | { 42 | pData->bIsOrdinal=false; 43 | pData->sFunction=pDebugger->read_ansiString(pData->_lpProcName); 44 | } 45 | #else 46 | if(pData->_lpProcName&0xFFFFFFFFFFFF0000) 47 | { 48 | pData->bIsOrdinal=false; 49 | pData->sFunction=pDebugger->read_ansiString(pData->_lpProcName); 50 | } 51 | #endif 52 | else 53 | { 54 | pData->bIsOrdinal=true; 55 | pData->nOrdinal=pData->_lpProcName; 56 | } 57 | } 58 | else if(handleType==HANDLE_TYPE_LEAVE) 59 | { 60 | pData->nResult=pDebugger->getFunctionResult(pFunctionInfo); 61 | } 62 | } 63 | 64 | void XWinAPI::handle_User32_MessageBox(XDebugger *pDebugger, XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,bool bIsUnicode,USER32_MESSAGEBOX *pData) 65 | { 66 | if(handleType==HANDLE_TYPE_ENTER) 67 | { 68 | *pData={}; 69 | 70 | pData->_hWnd=pDebugger->getFunctionParameter(pFunctionInfo,0); 71 | pData->_lpText=pDebugger->getFunctionParameter(pFunctionInfo,1); 72 | pData->_lpCaption=pDebugger->getFunctionParameter(pFunctionInfo,2); 73 | pData->_uType=pDebugger->getFunctionParameter(pFunctionInfo,3); 74 | 75 | pData->bIsUnicode=bIsUnicode; 76 | 77 | if(bIsUnicode) 78 | { 79 | pData->sText=pDebugger->read_unicodeString(pData->_lpText); 80 | pData->sCaption=pDebugger->read_unicodeString(pData->_lpCaption); 81 | } 82 | else 83 | { 84 | pData->sText=pDebugger->read_ansiString(pData->_lpText); 85 | pData->sCaption=pDebugger->read_ansiString(pData->_lpCaption); 86 | } 87 | } 88 | else if(handleType==HANDLE_TYPE_LEAVE) 89 | { 90 | pData->nResult=pDebugger->getFunctionResult(pFunctionInfo); 91 | } 92 | } 93 | 94 | void XWinAPI::handle_Kernel32_ExitProcess(XDebugger *pDebugger, XDebugger::FUNCTION_INFO *pFunctionInfo,HANDLE_TYPE handleType,KERNEL32_EXITPROCESS *pData) 95 | { 96 | if(handleType==HANDLE_TYPE_ENTER) 97 | { 98 | *pData={}; 99 | 100 | pData->_uExitCode=pDebugger->getFunctionParameter(pFunctionInfo,0); 101 | } 102 | else if(handleType==HANDLE_TYPE_LEAVE) 103 | { 104 | pData->nResult=pDebugger->getFunctionResult(pFunctionInfo); 105 | } 106 | } 107 | 108 | void XWinAPI::handle_Kernel32_VirtualAlloc(XDebugger *pDebugger, XDebugger::FUNCTION_INFO *pFunctionInfo, XWinAPI::HANDLE_TYPE handleType,KERNEL32_VIRTUALALLOC *pData) 109 | { 110 | if(handleType==HANDLE_TYPE_ENTER) 111 | { 112 | *pData={}; 113 | 114 | pData->_lpAddress=pDebugger->getFunctionParameter(pFunctionInfo,0); 115 | pData->_dwSize=pDebugger->getFunctionParameter(pFunctionInfo,1); 116 | pData->_flAllocationType=pDebugger->getFunctionParameter(pFunctionInfo,2); 117 | pData->_flProtect=pDebugger->getFunctionParameter(pFunctionInfo,3); 118 | } 119 | else if(handleType==HANDLE_TYPE_LEAVE) 120 | { 121 | pData->nResult=pDebugger->getFunctionResult(pFunctionInfo); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /xdebugger.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #ifndef XDEBUGGER_H 22 | #define XDEBUGGER_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "windows.h" 29 | #include "xprocess.h" 30 | #include "xprocessdevice.h" 31 | #include "xpe.h" 32 | //#include "xdisasm.h" 33 | 34 | class XDebugger : public QObject 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | struct OPTIONS 40 | { 41 | bool bShowWindow; 42 | QString sArgument; 43 | }; 44 | 45 | enum MESSAGE_TYPE 46 | { 47 | MESSAGE_TYPE_UNKNOWN=0, 48 | MESSAGE_TYPE_INFO, 49 | MESSAGE_TYPE_WARNING, 50 | MESSAGE_TYPE_ERROR 51 | }; 52 | 53 | struct DLL_INFO 54 | { 55 | QString sName; 56 | QString sFileName; 57 | qint64 nImageBase; 58 | qint64 nImageSize; 59 | }; 60 | 61 | struct FUNCTION_INFO 62 | { 63 | qint64 nAddress; 64 | qint64 nRetAddress; 65 | QString sName; 66 | HANDLE hThread; 67 | qint64 nStackFrame; 68 | }; 69 | 70 | struct SEH_INFO 71 | { 72 | qint64 nAddress; 73 | HANDLE hThread; 74 | }; 75 | 76 | explicit XDebugger(QObject *parent=nullptr); 77 | void setData(QString sFileName,OPTIONS *pOptions); 78 | bool loadFile(QString sFileName,OPTIONS *pOptions=nullptr); 79 | HANDLE getProcessHandle(); 80 | QMap *getMapDLL(); 81 | quint64 getFunctionResult(FUNCTION_INFO *pFunctionInfo); 82 | quint64 getFunctionParameter(FUNCTION_INFO *pFunctionInfo,qint32 nNumber); // TODO call conversions 83 | bool readData(qint64 nAddress,char *pBuffer,qint32 nBufferSize); 84 | bool writeData(qint64 nAddress,char *pBuffer,qint32 nBufferSize); 85 | QByteArray read_array(qint64 nAddress,qint32 nSize); 86 | QString read_ansiString(qint64 nAddress,qint64 nMaxSize=256); 87 | QString read_unicodeString(qint64 nAddress,qint64 nMaxSize=256); 88 | quint8 read_uint8(qint64 nAddress); 89 | quint16 read_uint16(qint64 nAddress); 90 | quint32 read_uint32(qint64 nAddress); 91 | quint64 read_uint64(qint64 nAddress); 92 | void write_uint8(qint64 nAddress,quint8 nValue); 93 | void write_uint16(qint64 nAddress,quint16 nValue); 94 | void write_uint32(qint64 nAddress,quint32 nValue); 95 | void write_uint64(qint64 nAddress,quint64 nValue); 96 | 97 | qint64 findSignature(qint64 nAddress, qint64 nSize, QString sSignature); 98 | void skipFunction(HANDLE hThread, quint32 nNumberOfParameters,quint64 nResult); 99 | void stepInto(HANDLE hThread,QVariant vInfo=QVariant()); 100 | 101 | void stop(); 102 | void pause(); 103 | void resume(); 104 | void stepInto(); 105 | void stepOver(); 106 | void suspendThread(HANDLE hThread); 107 | void resumeThread(HANDLE hThread); 108 | 109 | bool dumpMemoryRegionToFile(QString sFilename,qint64 nAddress,qint64 nSize); 110 | bool isAddressInImage(qint64 nAddress); 111 | bool isAddressInStack(qint64 nAddress); 112 | 113 | struct FILE_INFO 114 | { 115 | quint16 nMachine; 116 | quint16 nCharacteristics; 117 | quint16 nMagic; 118 | quint16 nSubsystem; 119 | quint16 nDllcharacteristics; 120 | quint8 nMajorOperationSystemVersion; 121 | quint8 nMinorOperationSystemVersion; 122 | quint64 nImageBase; 123 | quint32 nResourceRVA; 124 | quint32 nResourceSize; 125 | bool bIsTLSPresent; 126 | quint32 nAddressOfEntryPoint; 127 | bool bIs64; 128 | }; 129 | 130 | struct TARGET_INFO 131 | { 132 | QString sFileName; 133 | qint64 nImageBase; 134 | qint64 nImageSize; 135 | qint64 nStartAddress; 136 | }; 137 | 138 | struct CREATEPROCESS_INFO 139 | { 140 | HANDLE hProcess; 141 | HANDLE hThread; 142 | QString sFileName; 143 | qint64 nImageBase; 144 | qint64 nStartAddress; 145 | qint64 nThreadLocalBase; 146 | qint64 nStackAddress; 147 | qint64 nStackSize; 148 | }; 149 | 150 | struct STATS 151 | { 152 | bool bProcessEP; 153 | bool bTargetDLLLoaded; 154 | bool bStepInto; 155 | QVariant vStepIntoInfo; 156 | QMap mapAPI; 157 | HANDLE hBPThread; 158 | }; 159 | 160 | struct CREATETHREAD_INFO 161 | { 162 | HANDLE hThread; 163 | qint64 nThreadLocalBase; 164 | qint64 nStartAddress; 165 | }; 166 | 167 | struct EXITPROCESS_INFO 168 | { 169 | qint32 nExitCode; 170 | }; 171 | 172 | struct EXITTHREAD_INFO 173 | { 174 | qint32 nExitCode; 175 | }; 176 | 177 | struct ENTRYPOINT_INFO 178 | { 179 | qint64 nAddress; 180 | HANDLE hThread; 181 | }; 182 | 183 | enum BP_TYPE 184 | { 185 | BP_TYPE_UNKNOWN=0, 186 | BP_TYPE_CC, 187 | BP_TYPE_HWEXE 188 | }; 189 | 190 | enum BP_INFO 191 | { 192 | BP_INFO_UNKNOWN=0, 193 | BP_INFO_PROCESS_ENTRYPOINT, 194 | BP_INFO_TARGETDLL_ENTRYPOINT, 195 | BP_INFO_API_ENTER, 196 | BP_INFO_API_LEAVE, 197 | BP_INFO_SEH, 198 | BP_INFO_USER 199 | }; 200 | 201 | struct BREAKPOINT_INSTR 202 | { 203 | qint64 nAddress; 204 | qint32 nCount; 205 | BP_TYPE bpType; 206 | BP_INFO bpInfo; 207 | QVariant vInfo; 208 | char origData[4]; 209 | qint32 nOrigDataSize; 210 | }; 211 | 212 | struct BREAKPOINT_HW 213 | { 214 | qint64 nAddress; 215 | qint32 nCount; 216 | BP_TYPE bpType; 217 | BP_INFO bpInfo; 218 | QVariant vInfo; 219 | HANDLE hThread; 220 | qint32 nIndex; 221 | }; 222 | 223 | struct STEP_INFO 224 | { 225 | qint64 nAddress; 226 | HANDLE hThread; 227 | QVariant vInfo; 228 | }; 229 | 230 | struct EXCEPTION_INFO 231 | { 232 | qint64 nAddress; 233 | qint64 nExceptionAddress; 234 | qint32 nExceptionCode; 235 | }; 236 | 237 | struct BREAKPOINT_INFO 238 | { 239 | qint64 nAddress; 240 | HANDLE hThread; 241 | BP_TYPE bpType; 242 | BP_INFO bpInfo; 243 | QVariant vInfo; 244 | }; 245 | 246 | enum REG_NAME 247 | { 248 | REG_NAME_EAX=0, 249 | REG_NAME_EBX, 250 | REG_NAME_ECX, 251 | REG_NAME_EDX, 252 | REG_NAME_ESI, 253 | REG_NAME_EDI, 254 | REG_NAME_EBP, 255 | REG_NAME_ESP, 256 | REG_NAME_EIP, 257 | REG_NAME_EFLAGS, 258 | #ifdef Q_OS_WIN64 259 | REG_NAME_RAX, 260 | REG_NAME_RBX, 261 | REG_NAME_RCX, 262 | REG_NAME_RDX, 263 | REG_NAME_RSI, 264 | REG_NAME_RDI, 265 | REG_NAME_RBP, 266 | REG_NAME_RSP, 267 | REG_NAME_RIP, 268 | REG_NAME_RFLAGS, 269 | REG_NAME_R8, 270 | REG_NAME_R9, 271 | REG_NAME_R10, 272 | REG_NAME_R11, 273 | REG_NAME_R12, 274 | REG_NAME_R13, 275 | REG_NAME_R14, 276 | REG_NAME_R15, 277 | #endif 278 | }; 279 | 280 | static QMap getRegState(HANDLE hThread); 281 | 282 | protected: 283 | virtual void _clear(); 284 | virtual void onFileLoad(XBinary *pBinary); 285 | virtual void onCreateProcessDebugEvent(CREATEPROCESS_INFO *pCreateProcessInfo); 286 | virtual void onCreateThreadDebugEvent(CREATETHREAD_INFO *pCreateThreadInfo); 287 | virtual void onExitProcessDebugEvent(EXITPROCESS_INFO *pExitProcessInfo) {Q_UNUSED(pExitProcessInfo)} 288 | virtual void onExitThreadDebugEvent(EXITTHREAD_INFO *pExitThreadInfo) {Q_UNUSED(pExitThreadInfo)} 289 | virtual void onLoadDllDebugEvent(DLL_INFO *pDllInfo); 290 | virtual void onUnloadDllDebugEvent(DLL_INFO *pDllInfo); 291 | virtual void onOutputDebugStringEvent(DEBUG_EVENT *pDebugEvent) {Q_UNUSED(pDebugEvent)} // TODO Check 292 | virtual void onRipEvent(DEBUG_EVENT *pDebugEvent) {Q_UNUSED(pDebugEvent)} 293 | virtual void onProcessEntryPoint(ENTRYPOINT_INFO *pEntryPointInfo) {Q_UNUSED(pEntryPointInfo)} 294 | virtual void onTargetEntryPoint(ENTRYPOINT_INFO *pEntryPointInfo); 295 | virtual void onBreakPoint(BREAKPOINT_INFO *pBreakPointInfo) {Q_UNUSED(pBreakPointInfo)} 296 | virtual void onFunctionEnter(FUNCTION_INFO *pFunctionInfo) {Q_UNUSED(pFunctionInfo)} 297 | virtual void onFunctionLeave(FUNCTION_INFO *pFunctionInfo) {Q_UNUSED(pFunctionInfo)} 298 | virtual void onSEH(SEH_INFO *pSEHInfo) {Q_UNUSED(pSEHInfo)} 299 | virtual void onStep(STEP_INFO *pStepInfo); 300 | virtual void onException(EXCEPTION_INFO *pExceptionInfo) {Q_UNUSED(pExceptionInfo)} 301 | // TODO onException 302 | 303 | bool setBP(HANDLE hThread,qint64 nAddress,BP_TYPE bpType=BP_TYPE_CC,BP_INFO bpInfo=BP_INFO_UNKNOWN,qint32 nCount=-1,QVariant vInfo=QVariant()); 304 | bool removeBP(HANDLE hThread,qint64 nAddress,XDebugger::BP_TYPE bpType); 305 | bool addAPIHook(HANDLE hThread, QString sFunctionName, BP_TYPE bpType=BP_TYPE_CC); 306 | bool removeAPIHook(QString sFunctionName); 307 | bool _addAPIHook(HANDLE hThread, DLL_INFO dllInfo, QString sFunctionName, BP_TYPE bpType); 308 | bool isAPIHook(QString sFunctionName); 309 | 310 | QString getFunctionNameByAddress(qint64 nAddress); 311 | 312 | quint64 getRegister(HANDLE hThread,REG_NAME regName); 313 | bool setRegister(HANDLE hThread,REG_NAME regName,quint64 nValue); 314 | TARGET_INFO *getTargetInfo(); 315 | FILE_INFO *getFileInfo(); 316 | qint64 _getRetAddress(HANDLE hThread); 317 | qint64 _getCurrentAddress(HANDLE hThread); 318 | void _messageString(MESSAGE_TYPE type,QString sText); 319 | 320 | private: 321 | bool _setIP(HANDLE hThread,qint64 nAddress); 322 | bool _setStep(HANDLE hThread); 323 | 324 | enum LOAD_TYPE 325 | { 326 | LOAD_TYPE_EXE, 327 | LOAD_TYPE_DLL 328 | }; 329 | 330 | enum HWBP_ACCESS 331 | { 332 | HWBP_ACCESS_EXECUTE=0, 333 | HWBP_ACCESS_READ, 334 | HWBP_ACCESS_READWRITE 335 | }; 336 | 337 | enum HWBP_SIZE 338 | { 339 | HWBP_SIZE_BYTE=0, 340 | HWBP_SIZE_WORD, 341 | HWBP_SIZE_DWORD, 342 | HWBP_SIZE_QWORD 343 | }; 344 | 345 | struct DBGREGS 346 | { 347 | quint64 regs[4]; 348 | quint64 nControl; 349 | quint64 nStatus; 350 | }; 351 | 352 | bool _loadFile(QString sFileName,LOAD_TYPE loadType,OPTIONS *pOptions=nullptr); 353 | void _getFileInfo(QString sFileName); 354 | void _handleBP(LOAD_TYPE loadType, BP_INFO bpInfo, qint64 nAddress, HANDLE hThread, BP_TYPE bpType, QVariant vInfo); 355 | qint32 _setHWBPX(HANDLE hThread,qint64 nAddress,HWBP_ACCESS access,HWBP_SIZE size); 356 | bool _removeHWBPX(HANDLE hThread,qint32 nIndex); 357 | bool _setDbgRegs(HANDLE hThread,DBGREGS *pDr); 358 | bool _getDbgRegs(HANDLE hThread,DBGREGS *pDr); 359 | 360 | bool _suspendOtherThreads(HANDLE hCurrentThread); 361 | bool _resumeOtherThreads(HANDLE hCurrentThread); 362 | 363 | public slots: 364 | void process(); 365 | void continueExecution(); 366 | 367 | signals: 368 | void messageString(quint32 nType,QString sText); 369 | void finished(); 370 | void _onFileLoad(XBinary *pBinary); 371 | void _onCreateProcessDebugEvent(XDebugger::CREATEPROCESS_INFO *pCreateProcessInfo); 372 | void _onTargetEntryPoint(XDebugger::ENTRYPOINT_INFO *pEntryPointInfo); 373 | void _onCreateThreadDebugEvent(XDebugger::CREATETHREAD_INFO *pCreateThreadInfo); 374 | void _onLoadDllDebugEvent(XDebugger::DLL_INFO *pDllInfo); 375 | void _onUnloadDllDebugEvent(XDebugger::DLL_INFO *pDllInfo); 376 | void _onStep(XDebugger::STEP_INFO *pStepInfo); 377 | void _continueExecution(); 378 | 379 | private: 380 | QString d_sFileName; 381 | XDebugger::OPTIONS *d_pOptions; 382 | 383 | XDebugger::OPTIONS options; 384 | quint32 nProcessId; 385 | CREATEPROCESS_INFO createProcessInfo; 386 | FILE_INFO fileInfo; 387 | TARGET_INFO targetInfo; 388 | STATS stats; 389 | QMap mapDLL; 390 | QMap mapBP_Instr; 391 | QMap mapBP_HW; 392 | QMap mapThreads; 393 | QMap mapAPIHooks; 394 | }; 395 | 396 | #endif // XDEBUGGER_H 397 | -------------------------------------------------------------------------------- /xunpacker.cpp: -------------------------------------------------------------------------------- 1 | // copyright (c) 2019-2025 hors 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "xunpacker.h" 22 | 23 | XUnpacker::XUnpacker(QObject *parent) : XDebugger(parent) 24 | { 25 | 26 | } 27 | 28 | bool XUnpacker::dumpToFile(QString sFileName, XUnpacker::DUMP_OPTIONS *pDumpOptions) 29 | { 30 | bool bResult=false; 31 | 32 | qint64 nImageBase=getTargetInfo()->nImageBase; 33 | qint64 nImageSize=getTargetInfo()->nImageSize; 34 | 35 | if(pDumpOptions->bPatchNWError6002) 36 | { 37 | if(!(getFileInfo()->bIs64)) 38 | { 39 | // 004947D5 |. 8B40 24 MOV EAX,DWORD PTR DS:[EAX+24] 40 | // 004947D8 |. C1E8 1F SHR EAX,1F 41 | // 004947DB |. F7D0 NOT EAX 42 | // 004947DD |. 83E0 01 AND EAX,00000001 43 | qint64 nNWAddress=findSignature(nImageBase,nImageSize,"8B4024C1E81FF7D083E001"); 44 | 45 | if(nNWAddress!=-1) 46 | { 47 | _messageString(MESSAGE_TYPE_WARNING,tr("NW Address found: 0x%1").arg(nNWAddress,0,16)); 48 | 49 | // 83 c8 50 | // AND ->OR 51 | write_uint8(nNWAddress+9,0xC8); 52 | } 53 | } 54 | } 55 | 56 | const int N_BUFFER_SIZE=0x1000; 57 | 58 | char buffer[N_BUFFER_SIZE]; 59 | 60 | QList listMR; 61 | XProcess::MEMORY_REGION mr={}; 62 | 63 | int _bData=false; 64 | 65 | // The first block is a header 66 | // TODO directories!!! 67 | 68 | qint64 nResourcesStart=S_ALIGN_DOWN(getFileInfo()->nResourceRVA,0x1000)+nImageBase; 69 | qint64 nResourcesEnd=S_ALIGN_UP(getFileInfo()->nResourceRVA+getFileInfo()->nResourceSize,0x1000)+nImageBase; 70 | 71 | for(qint64 nCurrentAddress=nImageBase+0x1000;nCurrentAddress=nResourcesStart)&&(nCurrentAddress=nImageBase+nImageSize) 97 | { 98 | bLastSection=true; 99 | } 100 | 101 | bool bData=false; 102 | 103 | if(readData(nCurrentAddress,buffer,N_BUFFER_SIZE)) 104 | { 105 | // TODO !!! 106 | if(XBinary::isEmptyData(buffer,N_BUFFER_SIZE)) 107 | { 108 | bData=false; 109 | QString sDebugString=QString("%1: %2").arg(tr("Empty data")).arg(nCurrentAddress-nImageBase,0,16); 110 | _messageString(MESSAGE_TYPE_INFO,sDebugString); 111 | } 112 | else 113 | { 114 | bData=true; 115 | QString sDebugString=QString("%1: %2").arg(tr("Not empty data")).arg(nCurrentAddress-nImageBase,0,16); 116 | _messageString(MESSAGE_TYPE_INFO,sDebugString); 117 | } 118 | } 119 | 120 | if(!bCreateNewSection) 121 | { 122 | if((!_bData)&&(bData)) 123 | { 124 | if(!bResources) 125 | { 126 | bCreateNewSection=true; 127 | } 128 | } 129 | } 130 | 131 | _bData=bData; 132 | 133 | if(((bData)&&(!bCreateNewSection))||(bResources)) 134 | { 135 | mr.nSize+=N_BUFFER_SIZE; 136 | } 137 | 138 | if(bCreateNewSection) 139 | { 140 | if(mr.nAddress) 141 | { 142 | listMR.append(mr); 143 | } 144 | if(bCreateNewSection) 145 | { 146 | mr.nAddress=nCurrentAddress; 147 | mr.nSize=0x1000; 148 | mr.mf=mf; 149 | } 150 | } 151 | 152 | if(bLastSection) 153 | { 154 | if(mr.nAddress) 155 | { 156 | listMR.append(mr); 157 | } 158 | } 159 | } 160 | 161 | // Fix 162 | QList listSH; 163 | 164 | int nCountMR=listMR.count(); 165 | 166 | for(int i=0;inImageBase-getFileInfo()->nImageBase; 202 | 203 | QMapIterator i(mapRelocBuildRecords); 204 | while(i.hasNext()) 205 | { 206 | i.next(); 207 | 208 | RELOC_BUILD_RECORD record=i.value(); 209 | 210 | #ifndef Q_OS_WIN64 211 | quint32 nValue=read_uint32(record.nPatchAddress); 212 | nValue-=nDelta; 213 | write_uint32(record.nPatchAddress,nValue); 214 | #else 215 | quint64 nValue=read_uint64(record.nPatchAddress); 216 | nValue-=nDelta; 217 | write_uint64(record.nPatchAddress,nValue); 218 | #endif 219 | } 220 | 221 | QByteArray baHeader=read_array(getTargetInfo()->nImageBase,0x200); 222 | 223 | QBuffer buBuffer; 224 | buBuffer.setBuffer(&baHeader); 225 | 226 | // QFile file; 227 | // file.setFileName(sFileName); 228 | 229 | // if(file.open(QIODevice::ReadWrite)) 230 | // { 231 | // file.write(baHeader.data(),baHeader.size()); 232 | 233 | // XPE pe(&file); 234 | 235 | if(buBuffer.open(QIODevice::ReadWrite)) 236 | { 237 | XPE pe(&buBuffer); 238 | 239 | pe.setOptionalHeader_AddressOfEntryPoint(pDumpOptions->nAddressOfEntryPoint); 240 | 241 | pe.setFileHeader_NumberOfSections(0); 242 | pe.setOptionalHeader_FileAlignment(0x200); 243 | pe.setOptionalHeader_SectionAlignment(0x1000); 244 | pe.setOptionalHeader_SizeOfHeaders(0x200); 245 | 246 | for(int i=0;i mapImport=getImportMap(); 266 | 267 | if(mapImport.size()) 268 | { 269 | pe.addImportSection(&mapImport); 270 | } 271 | 272 | if(getTargetInfo()->nImageBase!=(qint64)getFileInfo()->nImageBase) 273 | { 274 | _messageString(MESSAGE_TYPE_INFO,tr("Relocs present")); 275 | } 276 | 277 | QList listRelocs=getRelocsList(); 278 | 279 | if(listRelocs.size()) 280 | { 281 | pe.addRelocsSection(&listRelocs); 282 | } 283 | 284 | if(pDumpOptions->bFixChecksum) 285 | { 286 | pe.fixCheckSum(); 287 | } 288 | else 289 | { 290 | pe.setOptionalHeader_CheckSum(0); 291 | } 292 | 293 | // TODO virtual function 294 | 295 | bResult=true; 296 | 297 | // file.close(); 298 | buBuffer.close(); 299 | } 300 | 301 | if(bResult) 302 | { 303 | QFile file; 304 | file.setFileName(sFileName); 305 | 306 | if(file.open(QIODevice::ReadWrite)) 307 | { 308 | file.write(baHeader.data(),baHeader.size()); 309 | 310 | file.close(); 311 | } 312 | else 313 | { 314 | bResult=false; 315 | } 316 | } 317 | 318 | // QFile file; 319 | // file.setFileName(sFileName); 320 | 321 | // if(file.open(QIODevice::ReadWrite)) 322 | // { 323 | // file.write(baHeader.data(),baHeader.size()); 324 | 325 | // XPE pe(&file); 326 | 327 | // pe.setOptionalHeader_AddressOfEntryPoint(pDumpOptions->nAddressOfEntryPoint); 328 | // pe.setFileHeader_NumberOfSections(0); 329 | 330 | // for(int i=0;i mapImport=getImportMap(); 340 | 341 | // pe.addImportSection(&mapImport); 342 | 343 | // if(getCreateProcessInfo()->nImageBase!=getCreateProcessInfo()->headerInfo.nImageBase) 344 | // { 345 | // // TODO 346 | // qDebug("Relocs Present"); 347 | // } 348 | 349 | // bResult=true; 350 | 351 | // file.close(); 352 | // } 353 | 354 | return bResult; 355 | } 356 | 357 | QMap XUnpacker::getImportMap() 358 | { 359 | QMap mapResult; 360 | 361 | QMapIterator i(mapImportBuildRecords); 362 | while(i.hasNext()) 363 | { 364 | i.next(); 365 | 366 | IMPORT_BUILD_RECORD record=i.value(); 367 | 368 | QString sFunction; 369 | 370 | if(record.bIsOrdinal) 371 | { 372 | sFunction=QString::number(record.nOrdinal); 373 | } 374 | else 375 | { 376 | sFunction=record.sFunction; 377 | } 378 | 379 | mapResult.insert(record.nPatchAddress,record.sLibrary+"#"+sFunction); 380 | } 381 | 382 | return mapResult; 383 | } 384 | 385 | QList XUnpacker::getRelocsList() 386 | { 387 | QList listResult; 388 | 389 | QMapIterator i(mapRelocBuildRecords); 390 | while(i.hasNext()) 391 | { 392 | i.next(); 393 | 394 | RELOC_BUILD_RECORD record=i.value(); 395 | 396 | record.nPatchAddress-=getTargetInfo()->nImageBase; 397 | 398 | listResult.append(record.nPatchAddress); 399 | } 400 | 401 | return listResult; 402 | } 403 | 404 | QString XUnpacker::getResultFileName() 405 | { 406 | return sResultFileName; 407 | } 408 | 409 | bool XUnpacker::unpack(QString sFileName, QString sResultFileName, QList *pListUnpackOptions) 410 | { 411 | this->sResultFileName=sResultFileName; 412 | listUnpackOptions=*pListUnpackOptions; 413 | 414 | XDebugger::OPTIONS options={}; 415 | options.bShowWindow=true; 416 | 417 | return loadFile(sFileName,&options); 418 | } 419 | 420 | QList XUnpacker::getDefaultUnpackOptions() 421 | { 422 | QList listResult; 423 | 424 | { 425 | UNPACK_OPTIONS_RECORD record={}; 426 | 427 | record.nID=UNPACK_OPTIONS_ID_FIXCHECKSUM; 428 | record.sName="fixchecksum"; 429 | record.sDescription=tr("Fix checksum"); 430 | record.varType=UNPACK_OPTIONS_VAR_TYPE_BOOL; 431 | record.var=true; 432 | 433 | listResult.append(record); 434 | } 435 | { 436 | UNPACK_OPTIONS_RECORD record={}; 437 | 438 | record.nID=UNPACK_OPTIONS_ID_PATCHNW; 439 | record.sName="patchnw"; 440 | record.sDescription=tr("Patch NW Address(fix Error 6002)"); 441 | record.varType=UNPACK_OPTIONS_VAR_TYPE_BOOL; 442 | record.var=true; 443 | 444 | listResult.append(record); 445 | } 446 | 447 | return listResult; 448 | } 449 | 450 | QVariant XUnpacker::getUnpackOptionValue(quint32 nID) 451 | { 452 | QVariant varResult=0; 453 | 454 | int nCount=listUnpackOptions.count(); 455 | 456 | for(int i=0;i 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | #include "xdebugger.h" 22 | 23 | XDebugger::XDebugger(QObject *parent) : QObject(parent) 24 | { 25 | 26 | } 27 | 28 | void XDebugger::setData(QString sFileName, XDebugger::OPTIONS *pOptions) 29 | { 30 | d_sFileName=sFileName; 31 | d_pOptions=pOptions; 32 | } 33 | 34 | bool XDebugger::loadFile(QString sFileName, XDebugger::OPTIONS *pOptions) 35 | { 36 | bool bResult=false; 37 | 38 | // TODO Check 32/64 39 | if(!XPE::isDll(sFileName)) 40 | { 41 | bResult=_loadFile(sFileName,LOAD_TYPE_EXE,pOptions); 42 | } 43 | else 44 | { 45 | bResult=_loadFile(sFileName,LOAD_TYPE_DLL,pOptions); 46 | } 47 | 48 | return bResult; 49 | } 50 | 51 | HANDLE XDebugger::getProcessHandle() 52 | { 53 | return createProcessInfo.hProcess; 54 | } 55 | 56 | QMap *XDebugger::getMapDLL() 57 | { 58 | return &mapDLL; 59 | } 60 | 61 | bool XDebugger::setBP(HANDLE hThread, qint64 nAddress,BP_TYPE bpType, BP_INFO bpInfo, qint32 nCount, QVariant vInfo) 62 | { 63 | bool bResult=false; 64 | 65 | if(bpType==BP_TYPE_CC) 66 | { 67 | if(!mapBP_Instr.contains(nAddress)) 68 | { 69 | BREAKPOINT_INSTR bpInstr={}; 70 | bpInstr.nAddress=nAddress; 71 | bpInstr.nCount=nCount; 72 | bpInstr.bpInfo=bpInfo; 73 | bpInstr.bpType=bpType; 74 | bpInstr.vInfo=vInfo; 75 | 76 | bpInstr.nOrigDataSize=1; 77 | 78 | if(readData(nAddress,bpInstr.origData,bpInstr.nOrigDataSize)) 79 | { 80 | if(writeData(nAddress,(char *)"\xCC",bpInstr.nOrigDataSize)) // TODO Check 81 | { 82 | mapBP_Instr.insert(nAddress,bpInstr); 83 | 84 | bResult=true; 85 | } 86 | } 87 | } 88 | } 89 | else if(bpType==BP_TYPE_HWEXE) 90 | { 91 | if(!mapBP_HW.contains(nAddress)) 92 | { 93 | BREAKPOINT_HW bpHW={}; 94 | bpHW.nAddress=nAddress; 95 | bpHW.nCount=nCount; 96 | bpHW.bpInfo=bpInfo; 97 | bpHW.bpType=bpType; 98 | bpHW.vInfo=vInfo; 99 | 100 | qint32 nIndex=_setHWBPX(hThread,nAddress,HWBP_ACCESS_EXECUTE,HWBP_SIZE_BYTE); 101 | 102 | if(nIndex!=-1) 103 | { 104 | bpHW.nIndex=nIndex; 105 | bpHW.hThread=hThread; 106 | 107 | mapBP_HW.insert(nAddress,bpHW); 108 | 109 | bResult=true; 110 | } 111 | } 112 | } 113 | 114 | return bResult; 115 | } 116 | 117 | bool XDebugger::removeBP(HANDLE hThread,qint64 nAddress,XDebugger::BP_TYPE bpType) 118 | { 119 | bool bResult=false; 120 | 121 | if(bpType==BP_TYPE_CC) 122 | { 123 | if(mapBP_Instr.contains(nAddress)) 124 | { 125 | BREAKPOINT_INSTR bpInstr=mapBP_Instr.value(nAddress); 126 | 127 | if(bpInstr.bpType==BP_TYPE_CC) 128 | { 129 | if(writeData(nAddress,bpInstr.origData,bpInstr.nOrigDataSize)) 130 | { 131 | mapBP_Instr.remove(nAddress); 132 | 133 | bResult=true; 134 | } 135 | } 136 | } 137 | } 138 | else if(bpType==BP_TYPE_HWEXE) 139 | { 140 | if(mapBP_HW.contains(nAddress)) 141 | { 142 | BREAKPOINT_HW bpHW=mapBP_HW.value(nAddress); 143 | 144 | if(_removeHWBPX(hThread,bpHW.nIndex)) 145 | { 146 | mapBP_HW.remove(nAddress); 147 | 148 | bResult=true; 149 | } 150 | } 151 | } 152 | 153 | return bResult; 154 | } 155 | 156 | bool XDebugger::addAPIHook(HANDLE hThread,QString sFunctionName,BP_TYPE bpType) 157 | { 158 | bool bResult=false; 159 | 160 | if(sFunctionName!="") 161 | { 162 | QMapIterator i(mapDLL); 163 | 164 | while(i.hasNext()) 165 | { 166 | i.next(); 167 | 168 | DLL_INFO dllInfo=i.value(); 169 | 170 | if(_addAPIHook(hThread,dllInfo,sFunctionName,bpType)) 171 | { 172 | bResult=true; 173 | } 174 | } 175 | 176 | if(bResult) 177 | { 178 | if(!mapAPIHooks.contains(sFunctionName)) 179 | { 180 | mapAPIHooks.insert(sFunctionName,bpType); 181 | } 182 | } 183 | } 184 | 185 | return bResult; 186 | } 187 | 188 | bool XDebugger::removeAPIHook(QString sFunctionName) 189 | { 190 | if(sFunctionName!="") 191 | { 192 | { 193 | QMutableMapIterator iInstr(mapBP_Instr); 194 | 195 | QList listBPInstr; 196 | 197 | while(iInstr.hasNext()) 198 | { 199 | iInstr.next(); 200 | 201 | BREAKPOINT_INSTR bp=iInstr.value(); 202 | 203 | if(bp.vInfo.toString()==sFunctionName) 204 | { 205 | listBPInstr.append(bp); 206 | } 207 | } 208 | 209 | for(int i=0;i iHW(mapBP_HW); 217 | 218 | QList listBPHW; 219 | 220 | while(iHW.hasNext()) 221 | { 222 | iHW.next(); 223 | 224 | BREAKPOINT_HW bp=iHW.value(); 225 | 226 | if(bp.vInfo.toString()==sFunctionName) 227 | { 228 | listBPHW.append(bp); 229 | } 230 | } 231 | 232 | for(int i=0;ihThread,REG_NAME_EAX); 295 | #else 296 | return getRegister(pFunctionInfo->hThread,REG_NAME_RAX); 297 | #endif 298 | } 299 | 300 | quint64 XDebugger::getFunctionParameter(XDebugger::FUNCTION_INFO *pFunctionInfo, qint32 nNumber) 301 | { 302 | quint64 nResult=0; 303 | 304 | #ifndef Q_OS_WIN64 305 | qint64 _nStackAddress=pFunctionInfo->nStackFrame+4+4*nNumber; 306 | nResult=read_uint32(_nStackAddress); 307 | #else 308 | // The Microsoft x64 calling convention 309 | if(nNumber==0) 310 | { 311 | nResult=getRegister(pFunctionInfo->hThread,REG_NAME_RCX); 312 | } 313 | else if(nNumber==1) 314 | { 315 | nResult=getRegister(pFunctionInfo->hThread,REG_NAME_RDX); 316 | } 317 | else if(nNumber==2) 318 | { 319 | nResult=getRegister(pFunctionInfo->hThread,REG_NAME_R8); 320 | } 321 | else if(nNumber==3) 322 | { 323 | nResult=getRegister(pFunctionInfo->hThread,REG_NAME_R9); 324 | } 325 | else 326 | { 327 | // TODO Check 328 | qint64 _nStackAddress=pFunctionInfo->nStackFrame+8+8*(nNumber-4); 329 | nResult=read_uint64(_nStackAddress); 330 | } 331 | #endif 332 | 333 | return nResult; 334 | } 335 | 336 | bool XDebugger::readData(qint64 nAddress, char *pBuffer, qint32 nBufferSize) 337 | { 338 | return XProcess::readData(getProcessHandle(),nAddress,pBuffer,nBufferSize); 339 | } 340 | 341 | bool XDebugger::writeData(qint64 nAddress, char *pBuffer, qint32 nBufferSize) 342 | { 343 | return XProcess::writeData(getProcessHandle(),nAddress,pBuffer,nBufferSize); 344 | } 345 | 346 | QByteArray XDebugger::read_array(qint64 nAddress, qint32 nSize) 347 | { 348 | return XProcess::read_array(getProcessHandle(),nAddress,nSize); 349 | } 350 | 351 | QString XDebugger::read_ansiString(qint64 nAddress, qint64 nMaxSize) 352 | { 353 | return XProcess::read_ansiString(getProcessHandle(),nAddress,nMaxSize); 354 | } 355 | 356 | QString XDebugger::read_unicodeString(qint64 nAddress, qint64 nMaxSize) 357 | { 358 | return XProcess::read_unicodeString(getProcessHandle(),nAddress,nMaxSize); 359 | } 360 | 361 | quint8 XDebugger::read_uint8(qint64 nAddress) 362 | { 363 | return XProcess::read_uint8(getProcessHandle(),nAddress); 364 | } 365 | 366 | quint16 XDebugger::read_uint16(qint64 nAddress) 367 | { 368 | return XProcess::read_uint16(getProcessHandle(),nAddress); 369 | } 370 | 371 | quint32 XDebugger::read_uint32(qint64 nAddress) 372 | { 373 | return XProcess::read_uint32(getProcessHandle(),nAddress); 374 | } 375 | 376 | quint64 XDebugger::read_uint64(qint64 nAddress) 377 | { 378 | return XProcess::read_uint64(getProcessHandle(),nAddress); 379 | } 380 | 381 | void XDebugger::write_uint8(qint64 nAddress, quint8 nValue) 382 | { 383 | XProcess::write_uint8(getProcessHandle(),nAddress,nValue); 384 | } 385 | 386 | void XDebugger::write_uint16(qint64 nAddress, quint16 nValue) 387 | { 388 | XProcess::write_uint16(getProcessHandle(),nAddress,nValue); 389 | } 390 | 391 | void XDebugger::write_uint32(qint64 nAddress, quint32 nValue) 392 | { 393 | XProcess::write_uint32(getProcessHandle(),nAddress,nValue); 394 | } 395 | 396 | void XDebugger::write_uint64(qint64 nAddress, quint64 nValue) 397 | { 398 | XProcess::write_uint64(getProcessHandle(),nAddress,nValue); 399 | } 400 | 401 | qint64 XDebugger::findSignature(qint64 nAddress, qint64 nSize, QString sSignature) 402 | { 403 | qint64 nResult=-1; 404 | 405 | XProcessDevice xpd(this); 406 | 407 | if(xpd.openHandle(getProcessHandle(),nAddress,nSize,QIODevice::ReadOnly)) 408 | { 409 | XBinary binary(&xpd,true,nAddress); 410 | 411 | qint64 nOffset=binary.find_signature(0,nSize,sSignature); 412 | nResult=binary.offsetToAddress(nOffset); 413 | 414 | xpd.close(); 415 | } 416 | 417 | return nResult; 418 | } 419 | 420 | void XDebugger::skipFunction(HANDLE hThread, quint32 nNumberOfParameters, quint64 nResult) 421 | { 422 | #ifndef Q_OS_WIN64 423 | quint32 nESP=getRegister(hThread,REG_NAME_ESP); 424 | quint32 nRET=read_uint32(nESP); 425 | nESP+=4+4*nNumberOfParameters; 426 | setRegister(hThread,REG_NAME_ESP,nESP); 427 | setRegister(hThread,REG_NAME_EIP,nRET); 428 | setRegister(hThread,REG_NAME_EAX,(quint32)nResult); 429 | #else 430 | quint64 nRSP=getRegister(hThread,REG_NAME_RSP); 431 | quint64 nRET=read_uint64(nRSP); 432 | int _nNumbersOfArgs=qMax((qint32)nNumberOfParameters-4,0); 433 | nRSP+=8+8*_nNumbersOfArgs; 434 | setRegister(hThread,REG_NAME_RSP,nRSP); 435 | setRegister(hThread,REG_NAME_RIP,nRET); 436 | setRegister(hThread,REG_NAME_RAX,(quint64)nResult); 437 | #endif 438 | } 439 | 440 | void XDebugger::stepInto(HANDLE hThread,QVariant vInfo) 441 | { 442 | _setStep(hThread); 443 | stats.bStepInto=true; 444 | stats.vStepIntoInfo=vInfo; 445 | } 446 | 447 | void XDebugger::stop() 448 | { 449 | // TODO errors 450 | TerminateProcess(getProcessHandle(),0); 451 | } 452 | 453 | void XDebugger::pause() 454 | { 455 | QList listThreads=mapThreads.values(); 456 | 457 | int nCount=listThreads.count(); 458 | 459 | for(int i=0;i listThreads=mapThreads.values(); 468 | 469 | int nCount=listThreads.count(); 470 | 471 | for(int i=0;i stepInto 486 | // If call break point on the next instruction 487 | } 488 | 489 | void XDebugger::suspendThread(HANDLE hThread) 490 | { 491 | SuspendThread(hThread); 492 | } 493 | 494 | void XDebugger::resumeThread(HANDLE hThread) 495 | { 496 | ResumeThread(hThread); 497 | } 498 | 499 | bool XDebugger::dumpMemoryRegionToFile(QString sFilename, qint64 nAddress, qint64 nSize) 500 | { 501 | bool bResult=false; 502 | 503 | XProcessDevice xpd(this); 504 | 505 | if(xpd.openHandle(getProcessHandle(),nAddress,nSize,QIODevice::ReadOnly)) 506 | { 507 | XBinary binary(&xpd); 508 | 509 | bResult=binary.dumpToFile(sFilename,(qint64)0,nSize); 510 | 511 | xpd.close(); 512 | } 513 | 514 | return bResult; 515 | } 516 | 517 | bool XDebugger::isAddressInImage(qint64 nAddress) 518 | { 519 | bool bResult=false; 520 | 521 | if((targetInfo.nImageBase<=nAddress)&&(nAddress i(mapDLL); 546 | 547 | while(i.hasNext()) 548 | { 549 | i.next(); 550 | 551 | DLL_INFO dllInfo=i.value(); 552 | 553 | if((dllInfo.nImageBase<=nAddress)&&(nAddressapplicationDirPath()+QDir::separator()+"LibraryLoader32.exe"; 835 | #else 836 | _sFileName=qApp->applicationDirPath()+QDir::separator()+"LibraryLoader64.exe"; 837 | #endif 838 | _sArgument=QString("\"%1\" \"%2\"").arg(_sFileName).arg(sFileName); 839 | sTargetMD5=XBinary::getHash(XBinary::HASH_MD5,sFileName); 840 | // _sArgument=sFileName; 841 | _bCreateProcess=CreateProcessW((const wchar_t*)_sFileName.utf16(),(wchar_t*)_sArgument.utf16(),nullptr,nullptr,0,nFlags,nullptr,nullptr,&sturtupInfo,&processInfo); 842 | } 843 | 844 | if(_bCreateProcess) 845 | { 846 | nProcessId=processInfo.dwProcessId; 847 | 848 | if(ResumeThread(processInfo.hThread)!=((DWORD)-1)) 849 | { 850 | BREAKPOINT_INSTR bpRestoreInstr={}; 851 | bool bRestoreBPInstr=false; 852 | BREAKPOINT_HW bpRestoreHW={}; 853 | bool bRestoreBPHW=false; 854 | 855 | stats.bProcessEP=false; 856 | stats.bTargetDLLLoaded=false; 857 | 858 | // DWORD dwMainThreadID=0; 859 | 860 | while(true) 861 | { 862 | DEBUG_EVENT DBGEvent={0}; 863 | WaitForDebugEvent(&DBGEvent, INFINITE); 864 | 865 | quint32 nStatus=DBG_CONTINUE; 866 | 867 | if(DBGEvent.dwProcessId==nProcessId) 868 | { 869 | if(DBGEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT) 870 | { 871 | createProcessInfo.hProcess=DBGEvent.u.CreateProcessInfo.hProcess; 872 | createProcessInfo.hThread=DBGEvent.u.CreateProcessInfo.hThread; 873 | createProcessInfo.nImageBase=(qint64)DBGEvent.u.CreateProcessInfo.lpBaseOfImage; 874 | createProcessInfo.nStartAddress=(qint64)DBGEvent.u.CreateProcessInfo.lpStartAddress; 875 | createProcessInfo.sFileName=XProcess::getFileNameByHandle(DBGEvent.u.CreateProcessInfo.hFile); 876 | createProcessInfo.nThreadLocalBase=(qint64)DBGEvent.u.CreateProcessInfo.lpThreadLocalBase; 877 | 878 | #ifndef Q_OS_WIN64 879 | quint32 nSP=getRegister(createProcessInfo.hThread,REG_NAME_ESP); 880 | #else 881 | quint64 nSP=getRegister(createProcessInfo.hThread,REG_NAME_RSP); 882 | #endif 883 | createProcessInfo.nStackAddress=XProcess::getRegionAllocationBase(getProcessHandle(),nSP); 884 | createProcessInfo.nStackSize=XProcess::getRegionAllocationSize(getProcessHandle(),createProcessInfo.nStackAddress); 885 | 886 | if(loadType==LOAD_TYPE_EXE) 887 | { 888 | _getFileInfo(createProcessInfo.sFileName); 889 | 890 | targetInfo.sFileName=createProcessInfo.sFileName; 891 | targetInfo.nImageBase=createProcessInfo.nImageBase; 892 | targetInfo.nImageSize=XProcess::getRegionAllocationSize(getProcessHandle(),createProcessInfo.nImageBase); 893 | targetInfo.nStartAddress=createProcessInfo.nStartAddress; 894 | } 895 | 896 | setBP(createProcessInfo.hThread,createProcessInfo.nStartAddress,BP_TYPE_HWEXE,BP_INFO_PROCESS_ENTRYPOINT,1); 897 | 898 | mapThreads.insert(XProcess::getThreadIDByHandle(createProcessInfo.hThread),DBGEvent.u.CreateProcessInfo.hThread); 899 | 900 | // dwMainThreadID=DBGEvent.dwThreadId; 901 | 902 | onCreateProcessDebugEvent(&createProcessInfo); 903 | } 904 | else if(DBGEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT) 905 | { 906 | CREATETHREAD_INFO createThreadInfo={}; 907 | 908 | createThreadInfo.hThread=DBGEvent.u.CreateThread.hThread; 909 | createThreadInfo.nStartAddress=(qint64)DBGEvent.u.CreateThread.lpStartAddress; 910 | createThreadInfo.nThreadLocalBase=(qint64)DBGEvent.u.CreateThread.lpThreadLocalBase; 911 | 912 | mapThreads.insert(XProcess::getThreadIDByHandle(DBGEvent.u.CreateThread.hThread),DBGEvent.u.CreateThread.hThread); 913 | 914 | onCreateThreadDebugEvent(&createThreadInfo); 915 | } 916 | else if(DBGEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT) 917 | { 918 | EXITPROCESS_INFO exitProcessInfo={}; 919 | 920 | exitProcessInfo.nExitCode=(qint32)DBGEvent.u.ExitProcess.dwExitCode; 921 | 922 | mapThreads.remove(DBGEvent.dwThreadId); 923 | 924 | onExitProcessDebugEvent(&exitProcessInfo); 925 | 926 | break; 927 | } 928 | else if(DBGEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT) 929 | { 930 | EXITTHREAD_INFO exitThreadInfo={}; 931 | 932 | exitThreadInfo.nExitCode=(qint32)DBGEvent.u.ExitThread.dwExitCode; 933 | 934 | mapThreads.remove(DBGEvent.dwThreadId); 935 | 936 | onExitThreadDebugEvent(&exitThreadInfo); 937 | 938 | // Mb TODO exit main thread 939 | } 940 | else if(DBGEvent.dwDebugEventCode==LOAD_DLL_DEBUG_EVENT) 941 | { 942 | DLL_INFO dllInfo={}; 943 | dllInfo.nImageBase=(qint64)DBGEvent.u.LoadDll.lpBaseOfDll; 944 | dllInfo.nImageSize=XProcess::getRegionAllocationSize(getProcessHandle(),dllInfo.nImageBase); 945 | dllInfo.sFileName=XProcess::getFileNameByHandle(DBGEvent.u.LoadDll.hFile); 946 | dllInfo.sName=QFileInfo(dllInfo.sFileName).fileName(); 947 | 948 | HANDLE hThread=mapThreads.value(DBGEvent.dwThreadId); 949 | 950 | mapDLL.insert(dllInfo.nImageBase,dllInfo); 951 | 952 | // Add hooks if needed 953 | QMapIterator i(mapAPIHooks); 954 | 955 | while(i.hasNext()) 956 | { 957 | i.next(); 958 | 959 | QString sFunctionName=i.key(); 960 | BP_TYPE bpType=i.value(); 961 | _addAPIHook(hThread,dllInfo,sFunctionName,bpType); 962 | } 963 | 964 | onLoadDllDebugEvent(&dllInfo); 965 | 966 | if((stats.bProcessEP)&&(!stats.bTargetDLLLoaded)) 967 | { 968 | QString _sTargetMD5=XBinary::getHash(XBinary::HASH_MD5,dllInfo.sFileName); 969 | 970 | if(_sTargetMD5==sTargetMD5) 971 | { 972 | _getFileInfo(dllInfo.sFileName); 973 | 974 | targetInfo.sFileName=dllInfo.sFileName; 975 | targetInfo.nImageBase=dllInfo.nImageBase; 976 | targetInfo.nImageSize=XProcess::getRegionAllocationSize(getProcessHandle(),dllInfo.nImageBase); 977 | targetInfo.nStartAddress=fileInfo.nAddressOfEntryPoint+targetInfo.nImageBase; 978 | 979 | setBP(hThread,targetInfo.nStartAddress,BP_TYPE_HWEXE,BP_INFO_TARGETDLL_ENTRYPOINT,1); 980 | 981 | stats.bTargetDLLLoaded=true; 982 | } 983 | } 984 | } 985 | else if(DBGEvent.dwDebugEventCode==UNLOAD_DLL_DEBUG_EVENT) 986 | { 987 | qint64 nDllBase=(qint64)DBGEvent.u.UnloadDll.lpBaseOfDll; 988 | DLL_INFO dllInfo=mapDLL.value(nDllBase); 989 | 990 | mapDLL.remove(nDllBase); 991 | 992 | onUnloadDllDebugEvent(&dllInfo); 993 | } 994 | else if(DBGEvent.dwDebugEventCode==OUTPUT_DEBUG_STRING_EVENT) 995 | { 996 | onOutputDebugStringEvent(&DBGEvent); 997 | } 998 | else if(DBGEvent.dwDebugEventCode==RIP_EVENT) 999 | { 1000 | onRipEvent(&DBGEvent); 1001 | } 1002 | else if(DBGEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT) 1003 | { 1004 | EXCEPTION_DEBUG_INFO edi=DBGEvent.u.Exception; 1005 | qint64 nExceptionAddress=(qint64)edi.ExceptionRecord.ExceptionAddress; 1006 | quint32 nExceptionCode=(quint32)edi.ExceptionRecord.ExceptionCode; 1007 | HANDLE hThread=mapThreads.value(DBGEvent.dwThreadId); 1008 | // bool bIsFirtsChance=(edi.dwFirstChance==1); 1009 | // TODO Exceptions in TLS 1010 | // qDebug("Exception: %x",nExceptionAddress); 1011 | // qDebug("ExceptionCode: %x",nExceptionCode); 1012 | 1013 | nStatus=DBG_EXCEPTION_NOT_HANDLED; 1014 | 1015 | if((nExceptionCode==EXCEPTION_BREAKPOINT)||(nExceptionCode==0x4000001f )) // 4000001f WOW64 breakpoint 1016 | { 1017 | if(mapBP_Instr.contains(nExceptionAddress)) 1018 | { 1019 | stats.hBPThread=hThread; 1020 | 1021 | bool bThreadsSuspended=_suspendOtherThreads(hThread); 1022 | 1023 | BREAKPOINT_INSTR bpCC=mapBP_Instr.value(nExceptionAddress); 1024 | 1025 | if(bpCC.nCount!=-1) 1026 | { 1027 | bpCC.nCount--; 1028 | } 1029 | 1030 | if(bpCC.nCount) 1031 | { 1032 | bpRestoreInstr=bpCC; 1033 | bRestoreBPInstr=true; 1034 | } 1035 | 1036 | _setIP(mapThreads.value(DBGEvent.dwThreadId),nExceptionAddress); 1037 | 1038 | removeBP(hThread,nExceptionAddress,bpCC.bpType); 1039 | 1040 | _handleBP(loadType,bpCC.bpInfo,bpCC.nAddress,hThread,bpCC.bpType,bpCC.vInfo); 1041 | 1042 | if(bRestoreBPInstr) 1043 | { 1044 | _setStep(hThread); 1045 | } 1046 | 1047 | if(bThreadsSuspended) 1048 | { 1049 | _resumeOtherThreads(hThread); 1050 | } 1051 | 1052 | nStatus=DBG_CONTINUE; 1053 | } 1054 | else 1055 | { 1056 | 1057 | } 1058 | } 1059 | else if((nExceptionCode==EXCEPTION_SINGLE_STEP)||(nExceptionCode==0x4000001e)) // 4000001e WOW64 single step exception 1060 | { 1061 | if(bRestoreBPInstr) 1062 | { 1063 | setBP(hThread,bpRestoreInstr.nAddress,bpRestoreInstr.bpType,bpRestoreInstr.bpInfo,bpRestoreInstr.nCount,bpRestoreInstr.vInfo); 1064 | bRestoreBPInstr=false; 1065 | nStatus=DBG_CONTINUE; 1066 | } 1067 | 1068 | if(bRestoreBPHW) 1069 | { 1070 | setBP(hThread,bpRestoreHW.nAddress,bpRestoreHW.bpType,bpRestoreHW.bpInfo,bpRestoreHW.nCount,bpRestoreHW.vInfo); 1071 | bRestoreBPHW=false; 1072 | nStatus=DBG_CONTINUE; 1073 | } 1074 | 1075 | bool bThreadsSuspended=false; 1076 | 1077 | if(stats.bStepInto) 1078 | { 1079 | stats.hBPThread=hThread; 1080 | bThreadsSuspended=_suspendOtherThreads(hThread); 1081 | 1082 | STEP_INFO stepInfo={}; 1083 | 1084 | stepInfo.nAddress=nExceptionAddress; 1085 | stepInfo.hThread=hThread; 1086 | stepInfo.vInfo=stats.vStepIntoInfo; 1087 | 1088 | stats.bStepInto=false; 1089 | stats.vStepIntoInfo.clear(); 1090 | 1091 | onStep(&stepInfo); 1092 | 1093 | nStatus=DBG_CONTINUE; 1094 | } 1095 | 1096 | // Check HW 1097 | DBGREGS dr={}; 1098 | if(_getDbgRegs(hThread,&dr)) 1099 | { 1100 | for(int i=0; i<4; i++) 1101 | { 1102 | if(dr.nStatus&((quint64)1<regs[0]; 1439 | context.Dr1=pDr->regs[1]; 1440 | context.Dr2=pDr->regs[2]; 1441 | context.Dr3=pDr->regs[3]; 1442 | context.Dr6=pDr->nStatus; 1443 | context.Dr7=pDr->nControl; 1444 | 1445 | bResult=SetThreadContext(hThread,&context); 1446 | } 1447 | 1448 | return bResult; 1449 | } 1450 | 1451 | bool XDebugger::_getDbgRegs(HANDLE hThread, XDebugger::DBGREGS *pDr) 1452 | { 1453 | bool bResult=false; 1454 | 1455 | CONTEXT context= {0}; 1456 | context.ContextFlags=CONTEXT_ALL; 1457 | 1458 | if(GetThreadContext(hThread,&context)) 1459 | { 1460 | pDr->regs[0]=context.Dr0; 1461 | pDr->regs[1]=context.Dr1; 1462 | pDr->regs[2]=context.Dr2; 1463 | pDr->regs[3]=context.Dr3; 1464 | pDr->nStatus=context.Dr6; 1465 | pDr->nControl=context.Dr7; 1466 | 1467 | bResult=true; 1468 | } 1469 | 1470 | return bResult; 1471 | } 1472 | 1473 | bool XDebugger::_suspendOtherThreads(HANDLE hCurrentThread) 1474 | { 1475 | bool bResult=false; 1476 | 1477 | QList listThreads=mapThreads.values(); 1478 | 1479 | int nCount=listThreads.count(); 1480 | 1481 | // Suspend all other threads 1482 | for(int i=0;i listThreads=mapThreads.values(); 1500 | 1501 | int nCount=listThreads.count(); 1502 | 1503 | // Resume all other threads 1504 | for(int i=0;i XDebugger::getRegState(HANDLE hThread) 1535 | { 1536 | QMap mapResult; 1537 | 1538 | CONTEXT context={0}; 1539 | context.ContextFlags=CONTEXT_ALL; 1540 | 1541 | if(GetThreadContext(hThread,&context)) 1542 | { 1543 | #ifndef Q_OS_WIN64 1544 | mapResult.insert(REG_NAME_EAX,context.Eax); 1545 | mapResult.insert(REG_NAME_EBX,context.Ebx); 1546 | mapResult.insert(REG_NAME_ECX,context.Ecx); 1547 | mapResult.insert(REG_NAME_EDX,context.Edx); 1548 | mapResult.insert(REG_NAME_ESI,context.Esi); 1549 | mapResult.insert(REG_NAME_EDI,context.Edi); 1550 | mapResult.insert(REG_NAME_EBP,context.Ebp); 1551 | mapResult.insert(REG_NAME_ESP,context.Esp); 1552 | mapResult.insert(REG_NAME_EIP,context.Eip); 1553 | mapResult.insert(REG_NAME_EFLAGS,context.EFlags); 1554 | #else 1555 | mapResult.insert(REG_NAME_EAX,context.Rax); 1556 | mapResult.insert(REG_NAME_EAX,context.Rbx); 1557 | mapResult.insert(REG_NAME_EAX,context.Rcx); 1558 | mapResult.insert(REG_NAME_EAX,context.Rdx); 1559 | mapResult.insert(REG_NAME_EAX,context.Rsi); 1560 | mapResult.insert(REG_NAME_EAX,context.Rdi); 1561 | mapResult.insert(REG_NAME_EAX,context.Rbp); 1562 | mapResult.insert(REG_NAME_EAX,context.Rsp); 1563 | mapResult.insert(REG_NAME_EAX,context.Rip); 1564 | // TODO more regs 1565 | mapResult.insert(REG_NAME_EAX,context.EFlags); 1566 | #endif 1567 | } 1568 | 1569 | return mapResult; 1570 | } 1571 | 1572 | qint64 XDebugger::_getRetAddress(HANDLE hThread) 1573 | { 1574 | qint64 nResult=-1; 1575 | 1576 | #ifndef Q_OS_WIN64 1577 | quint64 nSP=getRegister(hThread,REG_NAME_ESP); 1578 | #else 1579 | quint64 nSP=getRegister(hThread,REG_NAME_RSP); 1580 | #endif 1581 | 1582 | if(nSP!=(quint64)-1) 1583 | { 1584 | #ifndef Q_OS_WIN64 1585 | nResult=read_uint32((qint64)nSP); 1586 | #else 1587 | nResult=read_uint64((qint64)nSP); 1588 | #endif 1589 | } 1590 | 1591 | return nResult; 1592 | } 1593 | 1594 | qint64 XDebugger::_getCurrentAddress(HANDLE hThread) 1595 | { 1596 | qint64 nResult=-1; 1597 | 1598 | #ifndef Q_OS_WIN64 1599 | nResult=getRegister(hThread,REG_NAME_EIP); 1600 | #else 1601 | nResult=getRegister(hThread,REG_NAME_RIP); 1602 | #endif 1603 | 1604 | return nResult; 1605 | } 1606 | --------------------------------------------------------------------------------