├── README.md ├── makefile ├── win32_debmod.cpp ├── win32_local_impl.cpp └── win32_user.cpp /README.md: -------------------------------------------------------------------------------- 1 | # IDA Debug Bridge 2 | 3 | IDA Debugger Module to Dynamically Synchronize Memory and Registers with third-party Backends (Tenet, Unicorn, GDB, etc.) 4 | 5 | By synchronizing the memory and registers with the IDA database, you can view the status of the program under debugging in the native window, and get a debugging experience seamlessly integrated with IDA. 6 | 7 | That means you can view variables inside the pseudo-code window in the debugging session, and get a better interactive debugging experience. 8 | 9 | ## Screenshot 10 | 11 | 12 | 13 | ## Installation 14 | 15 | This plugin currently only supports debugging sessions for PE and ELF programs on x86 or AMD64 architecture. 16 | 17 | Since this is only a project for Proof of Concept, only the source code of the plugin is provided. 18 | 19 | In order to build this plugin, you need to copy the content of this project and the source code of `jsoncpp` to the `dbg` folder of the IDA SDK. Edit the rules of the `makefile`. Then follow the instructions of `install_make.txt` in IDA SDK to make. 20 | 21 | After the compilation is complete, you need to copy the generated plugin to IDA's `plugins` directory. 22 | 23 | ## Usage 24 | 25 | ### Synchronize with Tenet 26 | 27 | You need to insert the following code in Tenet to synchronize memory and registers with IDA database via TCP connection on port 5000. 28 | 29 | Then follow the steps below. 30 | 31 | 1. Start the IDA process 32 | 2. Select IDA Debug Bridge debugger 33 | 3. Start a debugging session 34 | 4. Load Tenet trace file 35 | 36 | Now, you can explore the Time Travel Debugging experience seamlessly integrated with IDA. 37 | 38 | Insert the following code to `__init__()` inside `context.py`. 39 | 40 | ```python 41 | def server_loop(self,t): 42 | import json, socket 43 | host = '127.0.0.1' 44 | port = 5000 45 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 46 | s.bind((host, port)) 47 | s.listen(1) 48 | 49 | if self.arch.POINTER_SIZE == 8: 50 | REGISTERS = ["RAX","RBX","RCX","RDX","RSI","RDI","RBP","RSP","RIP","R8","R9","R10","R11","R12","R13","R14","R15"] 51 | else: 52 | REGISTERS = ["EAX","EBX","ECX","EDX","ESI","EDI","EBP","ESP","EIP"] 53 | 54 | while(True): 55 | client_socket, addr = s.accept() 56 | while True: 57 | data = client_socket.recv(1024).decode('utf-8') 58 | if not data: break 59 | print('TENET RECV: ',data) 60 | req = json.loads(data) 61 | if (req['func'] == 'dbg_read_memory'): 62 | mem = self.reader.get_memory(req['ea'],req['len']) 63 | output = [] 64 | for i in range(req['len']): 65 | if mem.mask[i] == 0xFF: 66 | output.append("%02X" % mem.data[i]) 67 | else: 68 | output.append("00") 69 | 70 | ret = ''.join(output) 71 | print('TENET SEND: ',ret) 72 | client_socket.send(json.dumps({'ret': ret}).encode('utf-8')) 73 | 74 | if (req['func'] == 'dbg_read_registers'): 75 | reg = self.reader.get_registers() 76 | ret = [] 77 | for i in REGISTERS: 78 | ret.append(reg[i]) 79 | 80 | print('TENET SEND: ',ret) 81 | client_socket.send(json.dumps({'ret': ret}).encode('utf-8')) 82 | 83 | client_socket.close() 84 | 85 | import _thread 86 | _thread.start_new_thread(self.server_loop,(self,)) 87 | ``` 88 | 89 | Insert the following code to `seek()` inside `reader.py` to automatically synchronize data. Or you can manually synchronize data by pressing F9. 90 | 91 | ```python 92 | import ida_dbg 93 | ida_dbg.continue_process() 94 | ``` 95 | 96 | ## Protocol 97 | 98 | ### Synchronize Registers 99 | 100 | Forwarded from IDA's `dbg_read_registers()` API. 101 | 102 | ```json 103 | {"func":"dbg_read_registers"} 104 | ``` 105 | 106 | ### Synchronize Memory 107 | 108 | Forwarded from IDA's `dbg_read_memory()` API. The parameters include the address and length of the memory area. 109 | 110 | ```json 111 | {"ea":140724733087136,"func":"dbg_read_memory","len":8} 112 | ``` 113 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | include ../../allmake.mak 2 | 3 | GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak 4 | GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak 5 | .PHONY: $(GOALS-1) 6 | all: $(GOALS-1) 7 | 8 | #---------------------------------------------------------------------- 9 | # ifdef __NT__ 10 | # ifndef __X86__ 11 | # SERVER = win64_remote$(B) 12 | # else 13 | # SERVER = win32_remote$(B) 14 | # endif 15 | # endif 16 | # ifdef SERVER 17 | # SERVERS += $(call server_exe,$(SERVER)) 18 | # endif 19 | 20 | # #---------------------------------------------------------------------- 21 | # STUB = $(call module_dll,win32_stub) 22 | # ifdef BUILD_IDA 23 | # ifeq ($(or $(IDAHOME),$(DEMO_OR_FREE)),) 24 | # MODULES += $(STUB) 25 | # endif 26 | # endif 27 | 28 | #---------------------------------------------------------------------- 29 | USER = $(call module_dll,win32_user) 30 | ifeq ($(and $(BUILD_IDA),$(__NT__)),1) 31 | MODULES += $(USER) 32 | endif 33 | 34 | #---------------------------------------------------------------------- 35 | # we explicitly added our module targets 36 | NO_DEFAULT_TARGETS = 1 37 | 38 | # NOTE: all MODULES must be defined before including plugin.mak. 39 | include ../plugin.mak 40 | # NOTE: target-specific rules and dependencies that use variable 41 | # expansion to name the target (such as "$(MODULE): [...]") must 42 | # come after including plugin.mak 43 | 44 | #---------------------------------------------------------------------- 45 | # select OBJS common to user plugin and debugger server 46 | BASE_OBJS-$(__NT__) += $(F)win32_debmod$(O) 47 | BASE_OBJS-$(__NT__) += $(F)win32_util$(O) 48 | BASE_OBJS-$(__NT__) += $(F)winbase_debmod$(O) 49 | BASE_OBJS-$(__NT__) += $(F)json_reader$(O) 50 | BASE_OBJS-$(__NT__) += $(F)json_value$(O) 51 | BASE_OBJS-$(__NT__) += $(F)json_writer$(O) 52 | BASE_OBJS += $(BASE_OBJS-1) 53 | 54 | #---------------------------------------------------------------------- 55 | SERVER_OBJS += $(F)win32_server$(O) 56 | SERVER_OBJS += $(F)tilfuncs$(O) 57 | SERVER_OBJS += $(BASE_OBJS) 58 | 59 | SERVER_STDLIBS += ole32.lib 60 | SERVER_STDLIBS += oleaut32.lib 61 | 62 | include ../server.mak 63 | 64 | #---------------------------------------------------------------------- 65 | STUB_OBJS += $(F)win32_stub$(O) 66 | STUB_OBJS += $(F)w32sehch$(O) 67 | $(STUB): MODULE_OBJS += $(STUB_OBJS) 68 | $(STUB): $(STUB_OBJS) 69 | 70 | #---------------------------------------------------------------------- 71 | USER_OBJS += $(F)win32_user$(O) 72 | USER_OBJS += $(F)w32sehch$(O) 73 | USER_OBJS += $(BASE_OBJS) 74 | $(USER): MODULE_OBJS += $(USER_OBJS) 75 | $(USER): $(USER_OBJS) 76 | $(USER): STDLIBS += user32.lib 77 | 78 | #---------------------------------------------------------------------- 79 | include $(IDA)objdir.mak 80 | 81 | # MAKEDEP dependency list ------------------ 82 | $(F)tilfuncs$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ 83 | $(I)diskio.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \ 84 | $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \ 85 | $(I)ins/pc.hpp $(I)intel.hpp $(I)kernwin.hpp \ 86 | $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)name.hpp \ 87 | $(I)netnode.hpp $(I)pro.h $(I)range.hpp \ 88 | $(I)segment.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \ 89 | ../../ldr/pe/cor.h ../../ldr/pe/corerror.h \ 90 | ../../ldr/pe/corhdr.h ../../ldr/pe/mycor.h \ 91 | ../../ldr/pe/pe.h ../../plugins/pdb/common.cpp \ 92 | ../../plugins/pdb/cvconst.h ../../plugins/pdb/dbghelp.h \ 93 | ../../plugins/pdb/dia2.h ../../plugins/pdb/idaaccess.hpp \ 94 | ../../plugins/pdb/msdia.cpp ../../plugins/pdb/msdia.hpp \ 95 | ../../plugins/pdb/pdb.hpp \ 96 | ../../plugins/pdb/pdbaccess.hpp \ 97 | ../../plugins/pdb/pdbida.hpp \ 98 | ../../plugins/pdb/pdblocal.cpp \ 99 | ../../plugins/pdb/pdblocal.hpp \ 100 | ../../plugins/pdb/varser.hpp ../debmod.h tilfuncs.cpp \ 101 | tilfuncs.hpp 102 | $(F)w32sehch$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ 103 | $(I)dbg.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \ 104 | $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp \ 105 | $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp $(I)name.hpp \ 106 | $(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \ 107 | $(I)ua.hpp $(I)xref.hpp w32sehch.cpp w32sehch.h 108 | $(F)win32_debmod$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \ 109 | $(I)config.hpp $(I)dbg.hpp $(I)diskio.hpp $(I)entry.hpp \ 110 | $(I)err.h $(I)exehdr.h $(I)fixup.hpp $(I)fpro.h \ 111 | $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \ 112 | $(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \ 113 | $(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \ 114 | $(I)offset.hpp $(I)pro.h $(I)prodir.h \ 115 | $(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \ 116 | $(I)xref.hpp ../../ldr/pe/../idaldr.h \ 117 | ../../ldr/pe/common.cpp ../../ldr/pe/common.h \ 118 | ../../ldr/pe/pe.h ../dbg_pe_hlp.cpp ../deb_pc.hpp \ 119 | ../debmod.h ../pc_debmod.h ../pc_regs.hpp \ 120 | win32_debmod.cpp win32_debmod.h win32_debmod_impl.cpp \ 121 | win32_rpc.h win32_undoc.h win32_util.hpp \ 122 | winbase_debmod.h 123 | $(F)win32_server$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ 124 | $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \ 125 | $(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \ 126 | $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \ 127 | $(I)pro.h $(I)range.hpp $(I)segment.hpp \ 128 | $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \ 129 | ../../ldr/pe/cor.h ../../ldr/pe/corerror.h \ 130 | ../../ldr/pe/corhdr.h ../../ldr/pe/mycor.h \ 131 | ../../ldr/pe/pe.h ../../plugins/pdb/cvconst.h \ 132 | ../../plugins/pdb/dia2.h ../../plugins/pdb/idaaccess.hpp \ 133 | ../../plugins/pdb/msdia.hpp ../../plugins/pdb/pdb.hpp \ 134 | ../../plugins/pdb/pdbaccess.hpp \ 135 | ../../plugins/pdb/pdbida.hpp \ 136 | ../../plugins/pdb/pdblocal.hpp ../dbg_rpc_hlp.h \ 137 | ../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \ 138 | tilfuncs.hpp win32_debmod.h win32_rpc.h win32_server.cpp \ 139 | win32_util.hpp winbase_debmod.h 140 | $(F)win32_stub$(O): $(I)../ldr/pe/pe.h $(I)../plugins/pdb/pdb.hpp \ 141 | $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ 142 | $(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \ 143 | $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \ 144 | $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \ 145 | $(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \ 146 | $(I)pro.h $(I)range.hpp $(I)segment.hpp \ 147 | $(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \ 148 | ../../ldr/pe/pe.h ../common_local_impl.cpp \ 149 | ../common_stub_impl.cpp ../dbg_rpc_client.h \ 150 | ../dbg_rpc_engine.h ../dbg_rpc_hlp.h ../deb_pc.hpp \ 151 | ../debmod.h ../pc_local_impl.cpp ../pc_regs.hpp \ 152 | ../rpc_debmod.h w32sehch.h win32_local_impl.cpp \ 153 | win32_rpc.h win32_stub.cpp 154 | $(F)win32_user$(O): $(I)../ldr/pe/pe.h $(I)../plugins/pdb/pdb.hpp \ 155 | $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \ 156 | $(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \ 157 | $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \ 158 | $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \ 159 | $(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \ 160 | $(I)pro.h $(I)range.hpp $(I)segment.hpp \ 161 | $(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \ 162 | ../../ldr/pe/pe.h ../common_local_impl.cpp \ 163 | ../common_stub_impl.cpp ../dbg_rpc_hlp.h ../deb_pc.hpp \ 164 | ../debmod.h ../pc_debmod.h ../pc_local_impl.cpp \ 165 | ../pc_regs.hpp w32sehch.h win32_debmod.h \ 166 | win32_local_impl.cpp win32_rpc.h win32_server_stub.cpp \ 167 | win32_user.cpp win32_util.hpp winbase_debmod.h 168 | $(F)win32_util$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp \ 169 | $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \ 170 | $(I)pro.h $(I)range.hpp $(I)segment.hpp \ 171 | $(I)ua.hpp $(I)xref.hpp ../deb_pc.hpp ../debmod.h \ 172 | ../pc_debmod.h ../pc_regs.hpp win32_util.cpp \ 173 | win32_util.hpp winbase_debmod.h 174 | $(F)winbase_debmod$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp \ 175 | $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp \ 176 | $(I)netnode.hpp $(I)pro.h $(I)range.hpp \ 177 | $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp ../deb_pc.hpp \ 178 | ../debmod.h ../pc_debmod.h ../pc_regs.hpp win32_util.hpp \ 179 | winbase_debmod.cpp winbase_debmod.h 180 | $(F)json_reader$(O): json_reader.cpp 181 | $(F)json_value$(O): json_value.cpp 182 | $(F)json_writer$(O): json_writer.cpp 183 | -------------------------------------------------------------------------------- /win32_debmod.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "win32_debmod.h" 16 | 17 | #include "json/json.h" 18 | 19 | #pragma comment (lib, "Ws2_32.lib") 20 | #pragma comment (lib, "Mswsock.lib") 21 | #pragma comment (lib, "AdvApi32.lib") 22 | 23 | #define DEFAULT_BUFLEN 0x100000 24 | #define DEFAULT_PORT "5000" 25 | 26 | #define LOG_FUNC() msg("%s\n",__FUNCTION__) 27 | 28 | char recvbuf[DEFAULT_BUFLEN]; 29 | 30 | int recvlen; 31 | 32 | int connect_server(char *sendbuf,int sendlen,char *recvbuf,int *recvlen) 33 | { 34 | WSADATA wsaData; 35 | SOCKET ConnectSocket = INVALID_SOCKET; 36 | struct addrinfo *result = NULL, 37 | *ptr = NULL, 38 | hints; 39 | int iResult; 40 | int recvbuflen = DEFAULT_BUFLEN; 41 | 42 | // Initialize Winsock 43 | iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 44 | if (iResult != 0) { 45 | printf("WSAStartup failed with error: %d\n", iResult); 46 | return 1; 47 | } 48 | 49 | ZeroMemory( &hints, sizeof(hints) ); 50 | hints.ai_family = AF_UNSPEC; 51 | hints.ai_socktype = SOCK_STREAM; 52 | hints.ai_protocol = IPPROTO_TCP; 53 | 54 | // Resolve the server address and port 55 | iResult = getaddrinfo("127.0.0.1", DEFAULT_PORT, &hints, &result); 56 | if ( iResult != 0 ) { 57 | printf("getaddrinfo failed with error: %d\n", iResult); 58 | WSACleanup(); 59 | return 1; 60 | } 61 | 62 | // Attempt to connect to an address until one succeeds 63 | for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) { 64 | 65 | // Create a SOCKET for connecting to server 66 | ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 67 | ptr->ai_protocol); 68 | if (ConnectSocket == INVALID_SOCKET) { 69 | printf("socket failed with error: %ld\n", WSAGetLastError()); 70 | WSACleanup(); 71 | return 1; 72 | } 73 | 74 | // Connect to server. 75 | iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 76 | if (iResult == SOCKET_ERROR) { 77 | closesocket(ConnectSocket); 78 | ConnectSocket = INVALID_SOCKET; 79 | continue; 80 | } 81 | break; 82 | } 83 | 84 | freeaddrinfo(result); 85 | 86 | if (ConnectSocket == INVALID_SOCKET) { 87 | printf("Unable to connect to server!\n"); 88 | WSACleanup(); 89 | return 1; 90 | } 91 | 92 | // Send an initial buffer 93 | iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 ); 94 | if (iResult == SOCKET_ERROR) { 95 | printf("send failed with error: %d\n", WSAGetLastError()); 96 | closesocket(ConnectSocket); 97 | WSACleanup(); 98 | return 1; 99 | } 100 | 101 | printf("Bytes Sent: %ld\n", iResult); 102 | 103 | // shutdown the connection since no more data will be sent 104 | iResult = shutdown(ConnectSocket, SD_SEND); 105 | if (iResult == SOCKET_ERROR) { 106 | printf("shutdown failed with error: %d\n", WSAGetLastError()); 107 | closesocket(ConnectSocket); 108 | WSACleanup(); 109 | return 1; 110 | } 111 | 112 | // Receive until the peer closes the connection 113 | do { 114 | 115 | iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); 116 | if ( iResult > 0 ){ 117 | printf("Bytes received: %d\n", iResult); 118 | *recvlen = iResult; 119 | } 120 | else if ( iResult == 0 ) 121 | printf("Connection closed\n"); 122 | else 123 | printf("recv failed with error: %d\n", WSAGetLastError()); 124 | 125 | } while( iResult > 0 ); 126 | 127 | // cleanup 128 | closesocket(ConnectSocket); 129 | WSACleanup(); 130 | 131 | return 0; 132 | } 133 | 134 | //------------------------------------------------------------------------- 135 | struct machine_thread_state_t 136 | { 137 | ea_t __eax; 138 | ea_t __ebx; 139 | ea_t __ecx; 140 | ea_t __edx; 141 | ea_t __edi; 142 | ea_t __esi; 143 | ea_t __ebp; 144 | ea_t __esp; 145 | ea_t __eip; 146 | #ifndef __X86__ 147 | ea_t __r8; 148 | ea_t __r9; 149 | ea_t __r10; 150 | ea_t __r11; 151 | ea_t __r12; 152 | ea_t __r13; 153 | ea_t __r14; 154 | ea_t __r15; 155 | #endif 156 | ea_t __eflags; 157 | ea_t __ss; 158 | ea_t __cs; 159 | ea_t __ds; 160 | ea_t __es; 161 | ea_t __fs; 162 | ea_t __gs; 163 | }; 164 | 165 | //------------------------------------------------------------------------- 166 | #define MMX_FPU_REG_DATA_SIZE 10 167 | //lint -e754 local struct member '' not referenced 168 | struct mmx_fpu_reg_t 169 | { 170 | char __data[MMX_FPU_REG_DATA_SIZE]; 171 | char __rsv[6]; 172 | }; 173 | CASSERT(sizeof(mmx_fpu_reg_t) == 16); 174 | 175 | //------------------------------------------------------------------------- 176 | struct xmm_reg_t 177 | { 178 | char __data[16]; 179 | }; 180 | CASSERT(sizeof(xmm_reg_t) == 16); 181 | //lint +e754 182 | 183 | //------------------------------------------------------------------------- 184 | struct machine_float_state_t 185 | { 186 | mmx_fpu_reg_t __fpu_stmm[8]; 187 | xmm_reg_t __fpu_xmm[16]; 188 | xmm_reg_t __fpu_ymmh[16]; 189 | 190 | uint32 __fpu_mxcsr; 191 | uint32 __fpu_fcw; 192 | uint32 __fpu_fsw; 193 | uint32 __fpu_ftw; 194 | }; 195 | 196 | //-------------------------------------------------------------------------- 197 | struct regctx_t : public regctx_base_t 198 | { 199 | win32_debmod_t &debmod; 200 | 201 | machine_thread_state_t cpu; 202 | machine_float_state_t fpu; 203 | 204 | regctx_t(dynamic_register_set_t &_idaregs, win32_debmod_t &_debmod); 205 | 206 | bool init(void); 207 | bool load(context_holder_t *out); 208 | bool store(const context_holder_t &ctxh); 209 | }; 210 | 211 | //-------------------------------------------------------------------------- 212 | regctx_t::regctx_t(dynamic_register_set_t &_idaregs, win32_debmod_t &_debmod) 213 | : regctx_base_t(_idaregs), debmod(_debmod) 214 | { 215 | memset(&cpu, 0, sizeof(cpu)); 216 | memset(&fpu, 0, sizeof(fpu)); 217 | 218 | idaregs.set_regclasses(x86_register_classes); 219 | } 220 | 221 | //-------------------------------------------------------------------------- 222 | //lint -esym(1762,regctx_t::init) could be made const 223 | bool regctx_t::init(void) 224 | { 225 | return (clsmask & X86_RC_ALL) != 0; 226 | } 227 | 228 | //-------------------------------------------------------------------------- 229 | bool regctx_t::load(context_holder_t *out) 230 | { 231 | return init() && debmod.get_thread_state(out, &cpu, &fpu, tid, clsmask); 232 | } 233 | 234 | //-------------------------------------------------------------------------- 235 | bool regctx_t::store(const context_holder_t &ctxh) 236 | { 237 | return debmod.set_thread_state(cpu, fpu, ctxh, tid, clsmask); 238 | } 239 | 240 | //-------------------------------------------------------------------------- 241 | 242 | #ifndef TH32CS_SNAPNOHEAPS 243 | #define TH32CS_SNAPNOHEAPS 0x0 244 | #endif 245 | #include "win32_debmod_impl.cpp" 246 | 247 | typedef HANDLE WINAPI OpenThread_t(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId); 248 | static OpenThread_t *_OpenThread = NULL; 249 | typedef HRESULT WINAPI GetThreadDescription_t(HANDLE hThread, PWSTR *threadDescription); 250 | static GetThreadDescription_t *_GetThreadDescription = NULL; 251 | 252 | #ifndef __X86__ 253 | typedef BOOL WINAPI Wow64GetThreadContext_t(HANDLE hThread, PWOW64_CONTEXT lpContext); 254 | typedef BOOL WINAPI Wow64SetThreadContext_t(HANDLE hThread, const WOW64_CONTEXT *lpContext); 255 | typedef BOOL WINAPI Wow64GetThreadSelectorEntry_t(HANDLE hThread, DWORD dwSelector, PWOW64_LDT_ENTRY lpSelectorEntry); 256 | static Wow64GetThreadContext_t *_Wow64GetThreadContext = NULL; 257 | static Wow64SetThreadContext_t *_Wow64SetThreadContext = NULL; 258 | static Wow64GetThreadSelectorEntry_t *_Wow64GetThreadSelectorEntry = NULL; 259 | #endif 260 | 261 | // Older SDKs (such as the one used for the ..._opt_s debug servers) 262 | // requires these defines 263 | #ifndef XSTATE_MASK_AVX 264 | # define XSTATE_MASK_AVX (XSTATE_MASK_GSSE) 265 | #endif // XSTATE_MASK_AVX 266 | #ifndef XSTATE_AVX 267 | # define XSTATE_AVX (XSTATE_GSSE) 268 | #endif // XSTATE_AVX 269 | 270 | #define CONTEXT_XSTATE_BIT 0x40 271 | 272 | // https://docs.microsoft.com/en-us/windows/desktop/debug/working-with-xstate-context 273 | // The definition of CONTEXT_XSTATE changed across SDKs. On older SDKs, where it would 274 | // have another value, it wasn't usable anyway, so it's safe to undefine & re-define it. 275 | #ifdef CONTEXT_XSTATE 276 | # if ((CONTEXT_XSTATE & CONTEXT_XSTATE_BIT) == 0) 277 | # undef CONTEXT_XSTATE 278 | # if defined(_M_X64) 279 | # define CONTEXT_XSTATE (0x00100040) 280 | # else 281 | # define CONTEXT_XSTATE (0x00010040) 282 | # endif 283 | # endif 284 | #endif 285 | 286 | 287 | //-------------------------------------------------------------------------- 288 | static int calc_ctxflags(int clsmask) 289 | { 290 | int ctxflags = CONTEXT_CONTROL|CONTEXT_INTEGER; 291 | if ( (clsmask & X86_RC_SEGMENTS) != 0 ) 292 | ctxflags |= CONTEXT_SEGMENTS; 293 | if ( (clsmask & (X86_RC_FPU|X86_RC_MMX)) != 0 ) 294 | ctxflags |= CONTEXT_FLOATING_POINT; 295 | if ( (clsmask & X86_RC_XMM) != 0 ) 296 | #ifndef __X86__ 297 | ctxflags |= CONTEXT_FLOATING_POINT; 298 | #else 299 | ctxflags |= CONTEXT_EXTENDED_REGISTERS; 300 | #endif 301 | if ( (clsmask & X86_RC_YMM) != 0 ) 302 | #ifndef __X86__ 303 | ctxflags |= CONTEXT_XSTATE|CONTEXT_FLOATING_POINT; 304 | #else 305 | ctxflags |= CONTEXT_XSTATE|CONTEXT_EXTENDED_REGISTERS; 306 | #endif 307 | return ctxflags; 308 | } 309 | 310 | //-------------------------------------------------------------------------- 311 | // assertions that ensure that the conversion between CONTEXT and WOW64_CONTEXT 312 | // is correct 313 | #ifdef __X86__ 314 | CASSERT(sizeof(FLOATING_SAVE_AREA) == 112); 315 | CASSERT(CONTEXT_CONTROL == 0x10001); 316 | CASSERT(CONTEXT_INTEGER == 0x10002); 317 | CASSERT(CONTEXT_SEGMENTS == 0x10004); 318 | CASSERT(CONTEXT_FLOATING_POINT == 0x10008); 319 | CASSERT(CONTEXT_DEBUG_REGISTERS == 0x10010); 320 | CASSERT(CONTEXT_EXTENDED_REGISTERS == 0x10020); 321 | #else 322 | CASSERT(sizeof(WOW64_FLOATING_SAVE_AREA) == 112); 323 | CASSERT(sizeof(XSAVE_FORMAT) == WOW64_MAXIMUM_SUPPORTED_EXTENSION); 324 | CASSERT(WOW64_CONTEXT_CONTROL == 0x10001); 325 | CASSERT(WOW64_CONTEXT_INTEGER == 0x10002); 326 | CASSERT(WOW64_CONTEXT_SEGMENTS == 0x10004); 327 | CASSERT(WOW64_CONTEXT_FLOATING_POINT == 0x10008); 328 | CASSERT(WOW64_CONTEXT_DEBUG_REGISTERS == 0x10010); 329 | CASSERT(WOW64_CONTEXT_EXTENDED_REGISTERS == 0x10020); 330 | #endif 331 | 332 | #ifndef __X86__ 333 | //-------------------------------------------------------------------------- 334 | inline int ctxflags_to_wow64(int ctxflags) 335 | { 336 | if ( (ctxflags & CONTEXT_FLOATING_POINT) != 0 ) 337 | ctxflags |= WOW64_CONTEXT_EXTENDED_REGISTERS; 338 | // XSTATE in WOW64 is handled in a separate context 339 | bool requires_xstate = (ctxflags & CONTEXT_XSTATE) == CONTEXT_XSTATE; 340 | if ( requires_xstate ) 341 | ctxflags |= WOW64_CONTEXT_FLOATING_POINT; 342 | ctxflags &= ~CONTEXT_XSTATE_BIT; 343 | ctxflags &= ~CONTEXT_AMD64; 344 | ctxflags |= WOW64_CONTEXT_i386; 345 | return ctxflags; // see CASSERTs anout CONTEXT_... bits above 346 | } 347 | 348 | //------------------------------------------------------------------------- 349 | static void WOW64_CONTEXT_to_CONTEXT( 350 | CONTEXT *out, 351 | const WOW64_CONTEXT &wow64ctx, 352 | int clsmask, 353 | PCONTEXT xstate_ctx, 354 | const context_helper_t &helper) 355 | { 356 | out->ContextFlags = calc_ctxflags(clsmask); 357 | 358 | if ( xstate_ctx != NULL && helper.xstate_helpers_loaded() ) 359 | helper.pfnCopyContext(out, CONTEXT_XSTATE, xstate_ctx); 360 | 361 | out->Dr0 = wow64ctx.Dr0; 362 | out->Dr1 = wow64ctx.Dr1; 363 | out->Dr2 = wow64ctx.Dr2; 364 | out->Dr3 = wow64ctx.Dr3; 365 | out->Dr6 = wow64ctx.Dr6; 366 | out->Dr7 = wow64ctx.Dr7; 367 | 368 | out->SegGs = wow64ctx.SegGs; 369 | out->SegFs = wow64ctx.SegFs; 370 | out->SegEs = wow64ctx.SegEs; 371 | out->SegDs = wow64ctx.SegDs; 372 | 373 | out->Rdi = wow64ctx.Edi; 374 | out->Rsi = wow64ctx.Esi; 375 | out->Rbx = wow64ctx.Ebx; 376 | out->Rdx = wow64ctx.Edx; 377 | out->Rcx = wow64ctx.Ecx; 378 | out->Rax = wow64ctx.Eax; 379 | 380 | out->Rbp = wow64ctx.Ebp; 381 | out->SegCs = wow64ctx.SegCs; 382 | out->EFlags = wow64ctx.EFlags; 383 | out->SegSs = wow64ctx.SegSs; 384 | out->Rip = wow64ctx.Eip; 385 | out->Rsp = wow64ctx.Esp; 386 | 387 | if ( (wow64ctx.ContextFlags & WOW64_CONTEXT_EXTENDED_REGISTERS) != 0 ) 388 | { 389 | memcpy(&out->FltSave, wow64ctx.ExtendedRegisters, sizeof(out->FltSave)); 390 | } 391 | else if ( (wow64ctx.ContextFlags & WOW64_CONTEXT_FLOATING_POINT) != 0 ) 392 | { 393 | out->FltSave.ControlWord = wow64ctx.FloatSave.ControlWord; 394 | out->FltSave.StatusWord = wow64ctx.FloatSave.StatusWord; 395 | out->FltSave.TagWord = wow64ctx.FloatSave.TagWord; 396 | out->FltSave.ErrorOffset = wow64ctx.FloatSave.ErrorOffset; 397 | out->FltSave.ErrorSelector = wow64ctx.FloatSave.ErrorSelector; 398 | out->FltSave.DataOffset = wow64ctx.FloatSave.DataOffset; 399 | out->FltSave.DataSelector = wow64ctx.FloatSave.DataSelector; 400 | memset(out->FltSave.FloatRegisters, 0, sizeof(out->FltSave.FloatRegisters)); 401 | for ( int i=0; i < 8; i++ ) 402 | memcpy(&out->FltSave.FloatRegisters[i], &wow64ctx.FloatSave.RegisterArea[i*10], 10); 403 | } 404 | } 405 | 406 | //-------------------------------------------------------------------------- 407 | static void CONTEXT_to_WOW64_CONTEXT( 408 | WOW64_CONTEXT *out, 409 | CONTEXT &ctx, 410 | PCONTEXT xstate_ctx, 411 | int clsmask, 412 | const context_helper_t &helper) 413 | { 414 | int cflags = calc_ctxflags(clsmask); 415 | int wflags = ctxflags_to_wow64(cflags); 416 | out->ContextFlags = wflags; 417 | 418 | if ( xstate_ctx != NULL && helper.xstate_helpers_loaded() ) 419 | helper.pfnCopyContext(xstate_ctx, CONTEXT_XSTATE, &ctx); 420 | 421 | out->Dr0 = ctx.Dr0; 422 | out->Dr1 = ctx.Dr1; 423 | out->Dr2 = ctx.Dr2; 424 | out->Dr3 = ctx.Dr3; 425 | out->Dr6 = ctx.Dr6; 426 | out->Dr7 = ctx.Dr7; 427 | 428 | out->SegGs = ctx.SegGs; 429 | out->SegFs = ctx.SegFs; 430 | out->SegEs = ctx.SegEs; 431 | out->SegDs = ctx.SegDs; 432 | 433 | out->Edi = ctx.Rdi; 434 | out->Esi = ctx.Rsi; 435 | out->Ebx = ctx.Rbx; 436 | out->Edx = ctx.Rdx; 437 | out->Ecx = ctx.Rcx; 438 | out->Eax = ctx.Rax; 439 | 440 | out->Ebp = ctx.Rbp; 441 | out->SegCs = ctx.SegCs; 442 | out->EFlags = ctx.EFlags; 443 | out->SegSs = ctx.SegSs; 444 | out->Eip = ctx.Rip; 445 | out->Esp = ctx.Rsp; 446 | 447 | if ( (wflags & WOW64_CONTEXT_FLOATING_POINT) != 0 ) 448 | { 449 | out->FloatSave.ControlWord = ctx.FltSave.ControlWord; 450 | out->FloatSave.StatusWord = ctx.FltSave.StatusWord; 451 | out->FloatSave.TagWord = ctx.FltSave.TagWord; 452 | out->FloatSave.ErrorOffset = ctx.FltSave.ErrorOffset; 453 | out->FloatSave.ErrorSelector = ctx.FltSave.ErrorSelector; 454 | out->FloatSave.DataOffset = ctx.FltSave.DataOffset; 455 | out->FloatSave.DataSelector = ctx.FltSave.DataSelector; 456 | for ( int i=0; i < 8; i++ ) 457 | memcpy(&out->FloatSave.RegisterArea[i*10], &ctx.FltSave.FloatRegisters[i], 10); 458 | } 459 | if ( (wflags & WOW64_CONTEXT_EXTENDED_REGISTERS) != 0 ) 460 | memcpy(out->ExtendedRegisters, &ctx.FltSave, sizeof(ctx.FltSave)); 461 | } 462 | 463 | #define Eip Rip 464 | #endif 465 | 466 | //------------------------------------------------------------------------- 467 | // https://docs.microsoft.com/en-us/windows/desktop/debug/working-with-xstate-context 468 | bool context_helper_t::create_context(context_holder_t *out, int *_ctxflags) 469 | { 470 | out->buffer.qclear(); 471 | out->buffer.clear(); 472 | int ctxsz = sizeof(CONTEXT); 473 | #define CONTEXT_REQUIRES_XSTATE() ((*_ctxflags & CONTEXT_XSTATE_BIT) == CONTEXT_XSTATE_BIT) 474 | if ( CONTEXT_REQUIRES_XSTATE() && !get_xstate_context_size(&ctxsz) ) 475 | *_ctxflags &= ~CONTEXT_XSTATE_BIT; 476 | out->buffer.resize(ctxsz); 477 | if ( CONTEXT_REQUIRES_XSTATE() ) 478 | { 479 | if ( pfnInitializeContext( 480 | out->buffer.begin(), 481 | *_ctxflags, 482 | &out->ptr, 483 | (DWORD *) &ctxsz) == FALSE ) 484 | { 485 | return false; 486 | } 487 | 488 | if ( pfnSetXStateFeaturesMask(out->ptr, XSTATE_MASK_AVX) == FALSE ) 489 | return false; 490 | } 491 | else 492 | { 493 | out->ptr = (PCONTEXT) out->buffer.begin(); 494 | out->ptr->ContextFlags = *_ctxflags; 495 | } 496 | return true; 497 | } 498 | 499 | //------------------------------------------------------------------------- 500 | bool context_helper_t::get_xstate_context_size(int *out_ctxsz) 501 | { 502 | if ( xstate_context_size < 0 ) 503 | { 504 | xstate_context_size = 0; 505 | const char *error = NULL; 506 | 507 | HINSTANCE h = GetModuleHandle(kernel32_dll); 508 | *(FARPROC*) &pfnGetEnabledXStateFeatures = GetProcAddress(h, "GetEnabledXStateFeatures"); 509 | *(FARPROC*) &pfnInitializeContext = GetProcAddress(h, "InitializeContext"); 510 | *(FARPROC*) &pfnGetXStateFeaturesMask = GetProcAddress(h, "GetXStateFeaturesMask"); 511 | *(FARPROC*) &pfnLocateXStateFeature = GetProcAddress(h, "LocateXStateFeature"); 512 | *(FARPROC*) &pfnSetXStateFeaturesMask = GetProcAddress(h, "SetXStateFeaturesMask"); 513 | *(FARPROC*) &pfnCopyContext = GetProcAddress(h, "CopyContext"); 514 | 515 | if ( pfnGetEnabledXStateFeatures != NULL 516 | && pfnInitializeContext != NULL 517 | && pfnGetXStateFeaturesMask != NULL 518 | && pfnLocateXStateFeature != NULL 519 | && pfnSetXStateFeaturesMask != NULL 520 | && pfnCopyContext != NULL ) 521 | { 522 | DWORD64 feature_mask; 523 | feature_mask = pfnGetEnabledXStateFeatures(); 524 | if ( (feature_mask & XSTATE_MASK_AVX) != 0 ) 525 | { 526 | DWORD context_size = 0; 527 | BOOL success = pfnInitializeContext( 528 | NULL, 529 | CONTEXT_ALL | CONTEXT_XSTATE, 530 | NULL, 531 | &context_size); 532 | 533 | if ( (success != FALSE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ) 534 | error = "InitializeContext failed"; 535 | else 536 | xstate_context_size = context_size; 537 | } 538 | else 539 | { 540 | error = "AVX feature not enabled"; 541 | } 542 | } 543 | else 544 | { 545 | error = "Couldn't retrieve AVX functions"; 546 | } 547 | 548 | if ( error != NULL ) 549 | msg("%s\n", error); 550 | } 551 | int ctxsz = xstate_context_size; 552 | bool ok = ctxsz > 0; 553 | if ( ok ) 554 | *out_ctxsz = ctxsz; 555 | return ok; 556 | } 557 | 558 | //------------------------------------------------------------------------- 559 | void context_helper_t::clear() 560 | { 561 | memset(this, 0, sizeof(*this)); 562 | xstate_context_size = -1; 563 | } 564 | 565 | //-------------------------------------------------------------------------- 566 | // Macro to test the DBG_FLAG_DONT_DISTURB flag 567 | #if 0 568 | #define NODISTURB_ASSERT(x) QASSERT(x) 569 | #else 570 | #define NODISTURB_ASSERT(x) 571 | #endif 572 | 573 | static int g_code = 0; 574 | 575 | //-------------------------------------------------------------------------- 576 | void win32_debmod_t::check_thread(bool must_be_main_thread) const 577 | { 578 | // TODO 579 | //LOG_FUNC(); 580 | // remote debugger uses only one thread 581 | if ( rpc != NULL ) 582 | return; 583 | 584 | // someone turned off debthread? 585 | if ( (debugger_flags & DBG_FLAG_DEBTHREAD) == 0 ) 586 | return; 587 | 588 | // local debugger uses 2 threads and we must be in the correct one 589 | QASSERT(30191, is_main_thread() == must_be_main_thread); 590 | } 591 | 592 | //-------------------------------------------------------------------------- 593 | static int utf16_to_utf8(char *buf, size_t bufsize, LPCWSTR unicode) 594 | { 595 | qstring res; 596 | utf16_utf8(&res, unicode); 597 | qstrncpy(buf, res.c_str(), bufsize); 598 | size_t n = res.length(); 599 | if ( n > bufsize ) 600 | n = bufsize; 601 | return (int)n; 602 | } 603 | 604 | //-------------------------------------------------------------------------- 605 | // try to locate full path of a dll name without full path 606 | // for example, toolhelp.dll -> c:\windows\toolhelp.dll 607 | static bool find_full_path(char *fname, size_t fnamesize, const char *process_path) 608 | { 609 | if ( fname[0] != '\0' && !qisabspath(fname) ) 610 | { 611 | char path[QMAXPATH]; 612 | char dir[QMAXPATH]; 613 | // check system directory 614 | GetSystemDirectory(dir, sizeof(dir)); 615 | qmakepath(path, sizeof(path), dir, fname, NULL); 616 | if ( qfileexist(path) ) 617 | { 618 | FOUND: 619 | qstrncpy(fname, path, fnamesize); 620 | return true; 621 | } 622 | // check current process directory 623 | if ( process_path[0] != '\0' && !qisabspath(process_path) ) 624 | { 625 | qdirname(dir, sizeof(dir), process_path); 626 | qmakepath(path, sizeof(path), dir, fname, NULL); 627 | if ( qfileexist(path) ) 628 | goto FOUND; 629 | } 630 | // check current directory 631 | if ( GetCurrentDirectory(sizeof(dir), dir) != 0 ) 632 | { 633 | qmakepath(path, sizeof(path), dir, fname, NULL); 634 | if ( qfileexist(path) ) 635 | goto FOUND; 636 | } 637 | return false; 638 | } 639 | return true; 640 | } 641 | 642 | //-------------------------------------------------------------------------- 643 | ssize_t win32_debmod_t::access_memory(eanat_t ea, void *buffer, ssize_t size, bool do_write, bool suspend) 644 | { 645 | // TODO 646 | //LOG_FUNC(); 647 | if ( process_handle == INVALID_HANDLE_VALUE ) 648 | return -1; 649 | 650 | NODISTURB_ASSERT(in_event != NULL || exiting); 651 | 652 | // stop all threads before accessing its memory 653 | if ( suspend ) 654 | suspend_all_threads(); 655 | 656 | ea = s0tops(ea); 657 | void *addr = (void *)ea; 658 | 659 | DWORD_PTR size_access = 0; 660 | const DWORD BADPROT = DWORD(-1); 661 | DWORD oldprotect = BADPROT; 662 | bool ok; 663 | 664 | while ( true ) 665 | { 666 | // try to access the memory 667 | 668 | ok = do_write 669 | ? WriteProcessMemory( 670 | process_handle, // handle of the process whose memory is accessed 671 | addr, // address to start access 672 | buffer, // address of buffer 673 | (DWORD)size, // number of bytes to access 674 | (PDWORD_PTR)&size_access) != 0// address of number of bytes accessed 675 | : ReadProcessMemory( 676 | process_handle, // handle of the process whose memory is accessed 677 | addr, // address to start access 678 | buffer, // address of buffer 679 | (DWORD)size, // number of bytes to access 680 | (PDWORD_PTR)&size_access) != 0;// address of number of bytes accessed 681 | 682 | // if we have changed the page protection, revert it 683 | if ( oldprotect != BADPROT ) 684 | { 685 | if ( !VirtualProtectEx( 686 | process_handle, // handle of the process whose memory is accessed 687 | addr, // address to start access 688 | (DWORD)size, // number of bytes to access 689 | oldprotect, 690 | &oldprotect) ) 691 | { 692 | deberr("VirtualProtectEx2(%p)", addr); 693 | } 694 | break; // do not attempt more than once 695 | } 696 | 697 | // bail out after a successful read/write 698 | if ( ok ) 699 | break; 700 | 701 | // bail out if it is not about "not enough access rights" 702 | // *or* ERROR_PARTIAL_COPY as, sometimes we may read/write 703 | // *only* parts of memory because of page breakpoints 704 | int code = GetLastError(); 705 | if ( code != ERROR_NOACCESS && code != ERROR_PARTIAL_COPY ) 706 | { 707 | deberr("%sProcessMemory(%p)", do_write ? "Write" : "Read", ea); 708 | break; 709 | } 710 | 711 | if ( code != ERROR_PARTIAL_COPY ) 712 | size_access = 0; // size_access may be spoiled after failed ReadProcessMemory 713 | 714 | // check if the address is valid 715 | MEMORY_BASIC_INFORMATION meminfo; 716 | if ( !VirtualQueryEx(process_handle, // handle of process 717 | addr, // address of region 718 | &meminfo, // address of information buffer 719 | sizeof(meminfo)) ) // size of buffer 720 | { 721 | size_access = 0; 722 | break; 723 | } 724 | 725 | // allow the desired access on the page 726 | if ( !VirtualProtectEx( 727 | process_handle, // handle of the process whose memory is accessed 728 | addr, // address to start access 729 | (DWORD)size, // number of bytes to access 730 | do_write ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ, 731 | &oldprotect) ) 732 | { 733 | deberr("VirtualProtectEx1(%08p, size=%d for %s)", ea, int(size), do_write ? "write" : "read"); 734 | break; 735 | } 736 | } 737 | 738 | if ( do_write && ok ) 739 | FlushInstructionCache( 740 | process_handle, // handle to process with cache to flush 741 | addr, // pointer to region to flush 742 | (DWORD)size); // length of region to flush 743 | 744 | if ( suspend ) 745 | resume_all_threads(); 746 | return size_access; 747 | } 748 | 749 | //-------------------------------------------------------------------------- 750 | ssize_t win32_debmod_t::_read_memory(eanat_t ea, void *buffer, size_t size, bool suspend) 751 | { 752 | //LOG_FUNC(); 753 | return access_memory(ea, buffer, size, false, suspend); 754 | } 755 | 756 | int index(char c){ 757 | if (c<='9') 758 | return c-'0'; 759 | else 760 | return c-'A'+10; 761 | } 762 | 763 | ssize_t idaapi win32_debmod_t::dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring * /*errbuf*/) 764 | { 765 | //LOG_FUNC(); 766 | check_thread(false); 767 | /* 768 | return _read_memory(ea, buffer, size, true); 769 | */ 770 | Json::Value sendroot,recvroot; 771 | Json::FastWriter writer; 772 | Json::Reader reader; 773 | sendroot["func"] = "dbg_read_memory"; 774 | sendroot["ea"] = ea; 775 | sendroot["len"] = size; 776 | const std::string json_file = writer.write(sendroot); 777 | connect_server((char *)json_file.c_str(), json_file.length(), recvbuf, &recvlen); 778 | reader.parse(std::string(recvbuf,recvlen), recvroot); 779 | const std::string ret = recvroot["ret"].asString(); 780 | unsigned char *buf = (unsigned char *)buffer; 781 | for (int i=0;i 0 ) 827 | { 828 | ResumeThread(h); 829 | ti.suspend_count--; 830 | } 831 | } 832 | 833 | //-------------------------------------------------------------------------- 834 | inline void win32_debmod_t::suspend_all_threads(bool raw) 835 | { 836 | // TODO 837 | //LOG_FUNC(); 838 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 839 | _sure_suspend_thread(p->second, raw); 840 | } 841 | 842 | //-------------------------------------------------------------------------- 843 | inline void win32_debmod_t::resume_all_threads(bool raw) 844 | { 845 | // TODO 846 | //LOG_FUNC(); 847 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 848 | _sure_resume_thread(p->second, raw); 849 | } 850 | 851 | //-------------------------------------------------------------------------- 852 | static int get_thread_suspend_count(HANDLE hThread) 853 | { 854 | DWORD dwSuspendCount = SuspendThread(hThread); 855 | ResumeThread(hThread); 856 | return dwSuspendCount; 857 | } 858 | 859 | //-------------------------------------------------------------------------- 860 | inline void win32_debmod_t::suspend_running_threads(threadvec_t &suspended) 861 | { 862 | //LOG_FUNC(); 863 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 864 | { 865 | thread_info_t t = p->second; 866 | t.suspend_count = get_thread_suspend_count(t.hThread); 867 | if ( t.suspend_count == 0 ) 868 | { 869 | _sure_suspend_thread(t); 870 | suspended.push_back(t); 871 | } 872 | } 873 | } 874 | 875 | //-------------------------------------------------------------------------- 876 | inline void win32_debmod_t::resume_suspended_threads(threadvec_t suspended) const 877 | { 878 | //LOG_FUNC(); 879 | threadvec_t::iterator p; 880 | for ( p = suspended.begin(); p != suspended.end(); ++p ) 881 | _sure_resume_thread(*p); 882 | } 883 | 884 | //-------------------------------------------------------------------------- 885 | size_t win32_debmod_t::add_dll(image_info_t &ii) 886 | { 887 | // TODO 888 | //LOG_FUNC(); 889 | dlls.insert(std::make_pair(ii.base, ii)); 890 | dlls_to_import.insert(ii.base); 891 | return (size_t)ii.imagesize; 892 | } 893 | 894 | //-------------------------------------------------------------------------- 895 | // is modname already present in the loaded module list? 896 | bool win32_debmod_t::module_present(const char *modname) 897 | { 898 | // TODO 899 | //LOG_FUNC(); 900 | // host process is not added to dlls, so check it first 901 | if ( process_path == modname ) 902 | return true; 903 | 904 | // check DLLs which we already know about 905 | for ( const auto &p : dlls ) 906 | { 907 | const image_info_t &ii = p.second; 908 | if ( ii.name == modname ) 909 | return true; 910 | } 911 | return false; 912 | } 913 | 914 | //-------------------------------------------------------------------------- 915 | // iterate all modules of the specified process 916 | // until the callback returns != 0 917 | int win32_debmod_t::for_each_module(DWORD _pid, module_cb_t module_cb, void *ud) 918 | { 919 | //LOG_FUNC(); 920 | int code = 0; 921 | 922 | module_snapshot_t msnap(get_tool_help()); 923 | MODULEENTRY32 me; 924 | for ( bool ok = msnap.first(TH32CS_SNAPNOHEAPS, _pid, &me); ok; ok = msnap.next(&me) ) 925 | { 926 | code = module_cb(this, &me, ud); 927 | if ( code != 0 ) 928 | break; 929 | } 930 | return code; 931 | } 932 | 933 | //-------------------------------------------------------------------------- 934 | // callback: get info about the main module of the debugger process 935 | //lint -e{818} 936 | int win32_debmod_t::get_dmi_cb(debmod_t *sess, MODULEENTRY32 *me32, void *ud) 937 | { 938 | //LOG_FUNC(); 939 | win32_debmod_t *_this = (win32_debmod_t *)sess; 940 | // if the module name doesn't correspond to the process name, 941 | // we continue to iterate 942 | char buf[QMAXPATH]; 943 | tchar_utf8(buf, me32->szModule, sizeof(buf)); 944 | if ( !_this->process_path.empty() && stricmp(buf, qbasename(_this->process_path.c_str())) != 0 ) 945 | return 0; 946 | 947 | // ok, this module corresponds to our debugged process 948 | modinfo_t &dmi = *(modinfo_t *)ud; 949 | dmi.name = _this->process_path; 950 | dmi.base = EA_T(me32->modBaseAddr); 951 | dmi.size = (asize_t)me32->modBaseSize; 952 | return 1; // we stop to iterate 953 | } 954 | 955 | //-------------------------------------------------------------------------- 956 | // Return module information on the currently debugged process 957 | void win32_debmod_t::get_debugged_module_info(modinfo_t *dmi) 958 | { 959 | //LOG_FUNC(); 960 | dmi->name[0] = '\0'; 961 | dmi->base = BADADDR; 962 | dmi->size = 0; 963 | dmi->rebase_to = BADADDR; 964 | for_each_module(pid, get_dmi_cb, dmi); 965 | } 966 | 967 | //-------------------------------------------------------------------------- 968 | void idaapi win32_debmod_t::dbg_stopped_at_debug_event( 969 | import_infos_t *, 970 | bool dlls_added, 971 | thread_name_vec_t *thr_names) 972 | { 973 | // TODO 974 | //LOG_FUNC(); 975 | if ( dlls_added ) 976 | { 977 | check_thread(true); 978 | // we will take advantage of this event to import information 979 | // about the exported functions from the loaded dlls and the 980 | // binary itself 981 | name_info_t &ni = *get_debug_names(); 982 | if ( !binary_to_import.name.empty() ) 983 | { 984 | const char *bin_path = binary_to_import.name.c_str(); 985 | linput_t *li = open_linput(bin_path, false); 986 | if ( li != NULL ) 987 | { 988 | get_pe_exports_from_path(bin_path, li, binary_to_import.base, ni); 989 | close_linput(li); 990 | } 991 | binary_to_import.name.clear(); 992 | } 993 | 994 | for ( easet_t::iterator p = dlls_to_import.begin(); p != dlls_to_import.end(); ) 995 | { 996 | get_dll_exports(dlls, *p, ni); 997 | p = dlls_to_import.erase(p); 998 | } 999 | } 1000 | 1001 | if ( thr_names != NULL ) 1002 | update_thread_names(thr_names); 1003 | } 1004 | 1005 | //-------------------------------------------------------------------------- 1006 | static void update_thread_description(thread_info_t &ti) 1007 | { 1008 | if ( _GetThreadDescription == NULL ) 1009 | return; 1010 | 1011 | PWSTR data; 1012 | HRESULT hr = _GetThreadDescription(ti.hThread, &data); 1013 | if ( SUCCEEDED(hr) ) 1014 | { 1015 | int data_sz = wcslen(data) * 2; // size in bytes 1016 | qstring newname; 1017 | if ( convert_encoding( 1018 | (bytevec_t*)&newname, 1019 | ENC_UTF16LE, ENC_UTF8, 1020 | (const uchar *)data, 1021 | data_sz) > 0 ) 1022 | { 1023 | if ( newname != ti.name ) 1024 | { 1025 | ti.name = newname.c_str(); // newname over allocated 1026 | ti.set_new_name(); 1027 | } 1028 | } 1029 | LocalFree(data); 1030 | } 1031 | } 1032 | 1033 | //-------------------------------------------------------------------------- 1034 | void win32_debmod_t::update_thread_names(thread_name_vec_t *thr_names) 1035 | { 1036 | // TODO 1037 | //LOG_FUNC(); 1038 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 1039 | { 1040 | thread_info_t &ti = p->second; 1041 | update_thread_description(ti); 1042 | if ( ti.is_new_name() ) 1043 | { 1044 | thread_name_t &tn = thr_names->push_back(); 1045 | tn.tid = ti.tid; 1046 | tn.name = ti.name; 1047 | ti.clr_new_name(); 1048 | } 1049 | } 1050 | } 1051 | 1052 | //-------------------------------------------------------------------------- 1053 | // return the address of an exported name 1054 | ea_t win32_debmod_t::get_dll_export( 1055 | const images_t &_dlls, 1056 | ea_t imagebase, 1057 | const char *exported_name) 1058 | { 1059 | //LOG_FUNC(); 1060 | ea_t ret = BADADDR; 1061 | 1062 | name_info_t ni; 1063 | if ( get_dll_exports(_dlls, imagebase, ni, exported_name) && !ni.addrs.empty() ) 1064 | ret = ni.addrs[0]; 1065 | return ret; 1066 | } 1067 | 1068 | //-------------------------------------------------------------------------- 1069 | win32_debmod_t::win32_debmod_t() 1070 | : expecting_debug_break(0), stop_at_ntdll_bpts(false) 1071 | { 1072 | // TODO 1073 | //LOG_FUNC(); 1074 | fake_suspend_event = false; 1075 | 1076 | pid = -1; 1077 | 1078 | // Reset handles 1079 | process_handle = INVALID_HANDLE_VALUE; 1080 | thread_handle = INVALID_HANDLE_VALUE; 1081 | redirin_handle = INVALID_HANDLE_VALUE; 1082 | redirout_handle = INVALID_HANDLE_VALUE; 1083 | 1084 | attach_evid = INVALID_HANDLE_VALUE; 1085 | attach_status = as_none; 1086 | 1087 | memset(&cpdi, 0, sizeof(cpdi)); 1088 | cpdi.hFile = INVALID_HANDLE_VALUE; // hFile 1089 | cpdi.hProcess = INVALID_HANDLE_VALUE; // hProcess 1090 | cpdi.hThread = INVALID_HANDLE_VALUE; // hThread 1091 | 1092 | winxp_step_thread = 0; 1093 | memset(&in_event, 0, sizeof(in_event)); 1094 | exiting = false; 1095 | pause_requested = false; 1096 | 1097 | broken_event_handle = NULL; 1098 | // we don't set platform name here because it will be inherited 1099 | // from winbase_debmod_t 1100 | 1101 | binary_to_import.base = BADADDR; 1102 | binary_to_import.size = 0; 1103 | binary_to_import.rebase_to = BADADDR; 1104 | 1105 | reg_ctx = nullptr; 1106 | } 1107 | 1108 | //-------------------------------------------------------------------------- 1109 | #define qoffsetof2(s, f) (qoffsetof(regctx_t, s) + qoffsetof(decltype(regctx_t::s), f)) 1110 | #define offset_size(s, f) qoffsetof2(s, f), sizeof(decltype(regctx_t::s)::f) 1111 | 1112 | //-------------------------------------------------------------------------- 1113 | static void clear_ival(const regctx_t * /*ctx*/, regval_t *value, void * /*user_data*/) 1114 | { 1115 | value->ival = 0; 1116 | } 1117 | 1118 | //-------------------------------------------------------------------------- 1119 | static void nop_write(regctx_t * /*ctx*/, const regval_t * /*value*/, void * /*user_data*/) 1120 | { 1121 | } 1122 | 1123 | //-------------------------------------------------------------------------- 1124 | static void ymm_read(const regctx_t *ctx, regval_t *value, void *user_data) 1125 | { 1126 | size_t ymm_reg_idx = size_t(user_data); 1127 | const uint128 *ptrl = (uint128 *) &ctx->fpu.__fpu_xmm[0]; 1128 | const uint128 *ptrh = (uint128 *) &ctx->fpu.__fpu_ymmh[0]; 1129 | uint8_t ymm[32]; 1130 | *(uint128 *) &ymm[ 0] = ptrl[ymm_reg_idx]; 1131 | *(uint128 *) &ymm[16] = ptrh[ymm_reg_idx]; 1132 | value->set_bytes(ymm, sizeof(ymm)); 1133 | } 1134 | 1135 | //-------------------------------------------------------------------------- 1136 | static void ymm_write(regctx_t *ctx, const regval_t *value, void *user_data) 1137 | { 1138 | size_t ymm_reg_idx = size_t(user_data); 1139 | const uint8_t *ymm = (const uint8_t *) value->get_data(); 1140 | uint128 *ptrl = (uint128 *) &ctx->fpu.__fpu_xmm[0]; 1141 | uint128 *ptrh = (uint128 *) &ctx->fpu.__fpu_ymmh[0]; 1142 | ptrl[ymm_reg_idx] = *(uint128 *) &ymm[ 0]; 1143 | ptrh[ymm_reg_idx] = *(uint128 *) &ymm[16]; 1144 | } 1145 | 1146 | //------------------------------------------------------------------------- 1147 | void win32_debmod_t::init_reg_ctx(void) 1148 | { 1149 | // TODO 1150 | //LOG_FUNC(); 1151 | reg_ctx = new regctx_t(idaregs, *this); 1152 | 1153 | #ifdef __EA64__ 1154 | if ( is64 ) 1155 | { 1156 | reg_ctx->add_ival(r_rax, offset_size(cpu, __eax)); 1157 | reg_ctx->add_ival(r_rbx, offset_size(cpu, __ebx)); 1158 | reg_ctx->add_ival(r_rcx, offset_size(cpu, __ecx)); 1159 | reg_ctx->add_ival(r_rdx, offset_size(cpu, __edx)); 1160 | reg_ctx->add_ival(r_rsi, offset_size(cpu, __esi)); 1161 | reg_ctx->add_ival(r_rdi, offset_size(cpu, __edi)); 1162 | reg_ctx->add_ival(r_rbp, offset_size(cpu, __ebp)); 1163 | sp_idx = reg_ctx->add_ival(r_rsp, offset_size(cpu, __esp)); 1164 | pc_idx = reg_ctx->add_ival(r_rip, offset_size(cpu, __eip)); 1165 | reg_ctx->add_ival(r_r8, offset_size(cpu, __r8)); 1166 | reg_ctx->add_ival(r_r9, offset_size(cpu, __r9)); 1167 | reg_ctx->add_ival(r_r10, offset_size(cpu, __r10)); 1168 | reg_ctx->add_ival(r_r11, offset_size(cpu, __r11)); 1169 | reg_ctx->add_ival(r_r12, offset_size(cpu, __r12)); 1170 | reg_ctx->add_ival(r_r13, offset_size(cpu, __r13)); 1171 | reg_ctx->add_ival(r_r14, offset_size(cpu, __r14)); 1172 | reg_ctx->add_ival(r_r15, offset_size(cpu, __r15)); 1173 | } 1174 | else 1175 | #endif 1176 | { 1177 | reg_ctx->add_ival(r_eax, offset_size(cpu, __eax)); 1178 | reg_ctx->add_ival(r_ebx, offset_size(cpu, __ebx)); 1179 | reg_ctx->add_ival(r_ecx, offset_size(cpu, __ecx)); 1180 | reg_ctx->add_ival(r_edx, offset_size(cpu, __edx)); 1181 | reg_ctx->add_ival(r_esi, offset_size(cpu, __esi)); 1182 | reg_ctx->add_ival(r_edi, offset_size(cpu, __edi)); 1183 | reg_ctx->add_ival(r_ebp, offset_size(cpu, __ebp)); 1184 | sp_idx = reg_ctx->add_ival(r_esp, offset_size(cpu, __esp)); 1185 | pc_idx = reg_ctx->add_ival(r_eip, offset_size(cpu, __eip)); 1186 | } 1187 | sr_idx = reg_ctx->add_ival(x86_registers[R_EFLAGS], offset_size(cpu, __eflags)); 1188 | 1189 | cs_idx = reg_ctx->add_ival(x86_registers[R_CS], offset_size(cpu, __cs)); 1190 | fs_idx = reg_ctx->add_ival(x86_registers[R_FS], offset_size(cpu, __fs)); 1191 | gs_idx = reg_ctx->add_ival(x86_registers[R_GS], offset_size(cpu, __gs)); 1192 | if ( is64 ) 1193 | { 1194 | ds_idx = reg_ctx->add_func(x86_registers[R_DS], clear_ival, nop_write); 1195 | es_idx = reg_ctx->add_func(x86_registers[R_ES], clear_ival, nop_write); 1196 | ss_idx = reg_ctx->add_func(x86_registers[R_SS], clear_ival, nop_write); 1197 | } 1198 | else 1199 | { 1200 | ds_idx = reg_ctx->add_ival(x86_registers[R_DS], offset_size(cpu, __ds)); 1201 | es_idx = reg_ctx->add_ival(x86_registers[R_ES], offset_size(cpu, __es)); 1202 | ss_idx = reg_ctx->add_ival(x86_registers[R_SS], offset_size(cpu, __ss)); 1203 | } 1204 | 1205 | // ST* 1206 | size_t offset = qoffsetof2(fpu, __fpu_stmm); 1207 | for ( size_t i = R_ST0; i <= R_ST7; i++, offset += 16 ) 1208 | reg_ctx->add_fval(x86_registers[i], offset, 10); 1209 | 1210 | // FPU control 1211 | reg_ctx->add_ival(x86_registers[R_CTRL], offset_size(fpu, __fpu_fcw)); 1212 | reg_ctx->add_ival(x86_registers[R_STAT], offset_size(fpu, __fpu_fsw)); 1213 | reg_ctx->add_ival(x86_registers[R_TAGS], offset_size(fpu, __fpu_ftw)); 1214 | 1215 | // MMX* 1216 | offset = qoffsetof2(fpu, __fpu_stmm); 1217 | for ( size_t i = R_MMX0; i <= R_MMX7; i++, offset += 16 ) 1218 | reg_ctx->add_data(x86_registers[i], offset, 8); 1219 | 1220 | // XMM* 1221 | offset = qoffsetof2(fpu, __fpu_xmm); 1222 | for ( size_t i = R_XMM0; i <= R_LAST_XMM; i++, offset += 16 ) 1223 | { 1224 | #ifdef __EA64__ 1225 | if ( !is64 && i >= R_XMM8 ) 1226 | break; 1227 | #endif 1228 | reg_ctx->add_data(x86_registers[i], offset, 16); 1229 | } 1230 | reg_ctx->add_ival(x86_registers[R_MXCSR], offset_size(fpu, __fpu_mxcsr)); 1231 | 1232 | // YMM* 1233 | for ( size_t i = R_YMM0; i <= R_LAST_YMM; i++ ) 1234 | { 1235 | #ifdef __EA64__ 1236 | if ( !is64 && i >= R_YMM8 ) 1237 | break; 1238 | #endif 1239 | reg_ctx->add_func(x86_registers[i], ymm_read, ymm_write, (void *) (i - R_YMM0)); 1240 | } 1241 | } 1242 | 1243 | //------------------------------------------------------------------------- 1244 | void win32_debmod_t::term_reg_ctx(void) 1245 | { 1246 | // TODO 1247 | //LOG_FUNC(); 1248 | _term_reg_ctx(); 1249 | } 1250 | 1251 | //-------------------------------------------------------------------------- 1252 | #ifndef __X86__ 1253 | # define FloatSave FltSave // FIXME: use XMM save area! 1254 | # define RegisterArea FloatRegisters 1255 | # define FPUREG_ENTRY_SIZE 16 1256 | # define XMMREG_PTR ((uchar *)&ctx.Xmm0) 1257 | # define XMMREG_MXCSR (ctx.FltSave.MxCsr) 1258 | #else 1259 | # define FltSave FloatSave 1260 | # define XMMREG_PTR ((uchar *)&ctx.ExtendedRegisters[0xA0]) 1261 | # define XMMREG_MXCSR (*(uint32 *)&ctx.ExtendedRegisters[0x18]) 1262 | # define FPUREG_ENTRY_SIZE 10 1263 | #endif 1264 | 1265 | #define FPUREG_PTR ((uchar *)ctx.FloatSave.RegisterArea) 1266 | 1267 | //------------------------------------------------------------------------- 1268 | bool win32_debmod_t::get_thread_state( 1269 | context_holder_t *out_ctxh, 1270 | machine_thread_state_t *out_regs, 1271 | machine_float_state_t *out_floats, 1272 | thid_t tid, 1273 | int clsmask) 1274 | { 1275 | // TODO 1276 | //LOG_FUNC(); 1277 | thread_info_t *ti = threads.get(tid); 1278 | if ( ti == nullptr || !ti->read_context(out_ctxh, clsmask) ) 1279 | return false; 1280 | CONTEXT &ctx = *out_ctxh->ptr; 1281 | memset(out_regs, 0, sizeof(*out_regs)); 1282 | memset(out_floats, 0, sizeof(*out_floats)); 1283 | 1284 | // if ( (clsmask & (X86_RC_GENERAL|X86_RC_SEGMENTS)) != 0 ) 1285 | { 1286 | #ifdef __X86__ 1287 | out_regs->__eax = ctx.Eax; 1288 | out_regs->__ebx = ctx.Ebx; 1289 | out_regs->__ecx = ctx.Ecx; 1290 | out_regs->__edx = ctx.Edx; 1291 | out_regs->__edi = ctx.Edi; 1292 | out_regs->__esi = ctx.Esi; 1293 | out_regs->__ebp = ctx.Ebp; 1294 | out_regs->__esp = ctx.Esp; 1295 | out_regs->__eip = ctx.Eip; 1296 | out_regs->__eflags = ctx.EFlags; 1297 | out_regs->__cs = ctx.SegCs; 1298 | out_regs->__fs = ctx.SegFs; 1299 | out_regs->__gs = ctx.SegGs; 1300 | out_regs->__ss = ctx.SegSs; 1301 | out_regs->__ds = ctx.SegDs; 1302 | out_regs->__es = ctx.SegEs; 1303 | #else 1304 | out_regs->__eax = ctx.Rax; 1305 | out_regs->__ebx = ctx.Rbx; 1306 | out_regs->__ecx = ctx.Rcx; 1307 | out_regs->__edx = ctx.Rdx; 1308 | out_regs->__edi = ctx.Rdi; 1309 | out_regs->__esi = ctx.Rsi; 1310 | out_regs->__ebp = ctx.Rbp; 1311 | out_regs->__esp = ctx.Rsp; 1312 | out_regs->__eip = ctx.Rip; 1313 | out_regs->__r8 = ctx.R8; 1314 | out_regs->__r9 = ctx.R9; 1315 | out_regs->__r10 = ctx.R10; 1316 | out_regs->__r11 = ctx.R11; 1317 | out_regs->__r12 = ctx.R12; 1318 | out_regs->__r13 = ctx.R13; 1319 | out_regs->__r14 = ctx.R14; 1320 | out_regs->__r15 = ctx.R15; 1321 | out_regs->__eflags = ctx.EFlags; 1322 | out_regs->__cs = ctx.SegCs; 1323 | out_regs->__fs = ctx.SegFs; 1324 | out_regs->__gs = ctx.SegGs; 1325 | out_regs->__ss = ctx.SegSs; 1326 | out_regs->__ds = ctx.SegDs; 1327 | out_regs->__es = ctx.SegEs; 1328 | #endif 1329 | } 1330 | 1331 | if ( (clsmask & (X86_RC_FPU|X86_RC_MMX)) != 0 ) 1332 | { 1333 | if ( (clsmask & X86_RC_FPU) != 0 ) 1334 | { 1335 | out_floats->__fpu_fcw = ctx.FltSave.ControlWord; 1336 | out_floats->__fpu_fsw = ctx.FltSave.StatusWord; 1337 | out_floats->__fpu_ftw = ctx.FltSave.TagWord; 1338 | } 1339 | 1340 | const uchar *vptr = (const uchar *) FPUREG_PTR; 1341 | for ( int i = 0; i < 8; ++i, vptr += FPUREG_ENTRY_SIZE ) 1342 | memcpy(&out_floats->__fpu_stmm[i], vptr, MMX_FPU_REG_DATA_SIZE); 1343 | } 1344 | 1345 | if ( (clsmask & (X86_RC_XMM|X86_RC_YMM)) != 0 ) 1346 | { 1347 | const uchar *xptr = XMMREG_PTR; 1348 | memcpy(&out_floats->__fpu_xmm[0], xptr, (R_MXCSR - R_XMM0) * sizeof(xmm_reg_t)); 1349 | out_floats->__fpu_mxcsr = XMMREG_MXCSR; 1350 | } 1351 | 1352 | if ( (clsmask & X86_RC_YMM) != 0 1353 | && context_helper.xstate_helpers_loaded() 1354 | && context_helper.pfnSetXStateFeaturesMask(&ctx, XSTATE_MASK_AVX) != FALSE ) 1355 | { 1356 | DWORD xmm_blob_length = 0; 1357 | PM128A Xmm = (PM128A) context_helper.pfnLocateXStateFeature( 1358 | &ctx, 1359 | XSTATE_LEGACY_SSE, 1360 | &xmm_blob_length); 1361 | PM128A Ymm = (PM128A) context_helper.pfnLocateXStateFeature( 1362 | &ctx, 1363 | XSTATE_AVX, 1364 | NULL); 1365 | CASSERT(sizeof(Ymm[0]) == sizeof(xmm_reg_t)); 1366 | const int nxmm_regs = xmm_blob_length / sizeof(Xmm[0]); 1367 | const int nymm_regs = qmin(nxmm_regs, 16); 1368 | memcpy(&out_floats->__fpu_ymmh[0], Ymm, nymm_regs * sizeof(xmm_reg_t)); 1369 | } 1370 | 1371 | return true; 1372 | } 1373 | 1374 | //------------------------------------------------------------------------- 1375 | bool win32_debmod_t::set_thread_state( 1376 | const machine_thread_state_t &state, 1377 | const machine_float_state_t &floats, 1378 | const context_holder_t &ctxh, 1379 | thid_t tid, 1380 | int clsmask) 1381 | { 1382 | // TODO 1383 | //LOG_FUNC(); 1384 | thread_info_t *ti = threads.get(tid); 1385 | if ( ti == nullptr ) 1386 | return false; 1387 | 1388 | CONTEXT &ctx = *ctxh.ptr; 1389 | 1390 | // if ( (clsmask & (X86_RC_GENERAL|X86_RC_SEGMENTS)) != 0 ) 1391 | { 1392 | #ifdef __X86__ 1393 | ctx.Eax = state.__eax; 1394 | ctx.Ebx = state.__ebx; 1395 | ctx.Ecx = state.__ecx; 1396 | ctx.Edx = state.__edx; 1397 | ctx.Edi = state.__edi; 1398 | ctx.Esi = state.__esi; 1399 | ctx.Ebp = state.__ebp; 1400 | ctx.Esp = state.__esp; 1401 | ctx.Eip = state.__eip; 1402 | ctx.EFlags = state.__eflags; 1403 | ctx.SegCs = state.__cs; 1404 | ctx.SegFs = state.__fs; 1405 | ctx.SegGs = state.__gs; 1406 | ctx.SegSs = state.__ss; 1407 | ctx.SegDs = state.__ds; 1408 | ctx.SegEs = state.__es; 1409 | #else 1410 | ctx.Rax = state.__eax; 1411 | ctx.Rbx = state.__ebx; 1412 | ctx.Rcx = state.__ecx; 1413 | ctx.Rdx = state.__edx; 1414 | ctx.Rdi = state.__edi; 1415 | ctx.Rsi = state.__esi; 1416 | ctx.Rbp = state.__ebp; 1417 | ctx.Rsp = state.__esp; 1418 | ctx.Rip = state.__eip; 1419 | ctx.R8 = state.__r8; 1420 | ctx.R9 = state.__r9; 1421 | ctx.R10 = state.__r10; 1422 | ctx.R11 = state.__r11; 1423 | ctx.R12 = state.__r12; 1424 | ctx.R13 = state.__r13; 1425 | ctx.R14 = state.__r14; 1426 | ctx.R15 = state.__r15; 1427 | ctx.EFlags = state.__eflags; 1428 | ctx.SegCs = state.__cs; 1429 | ctx.SegFs = state.__fs; 1430 | ctx.SegGs = state.__gs; 1431 | ctx.SegSs = state.__ss; 1432 | ctx.SegDs = state.__ds; 1433 | ctx.SegEs = state.__es; 1434 | #endif 1435 | } 1436 | 1437 | if ( (clsmask & (X86_RC_FPU|X86_RC_MMX)) != 0 ) 1438 | { 1439 | if ( (clsmask & X86_RC_FPU) != 0 ) 1440 | { 1441 | ctx.FloatSave.ControlWord = floats.__fpu_fcw; 1442 | ctx.FloatSave.StatusWord = floats.__fpu_fsw; 1443 | ctx.FloatSave.TagWord = floats.__fpu_ftw; 1444 | } 1445 | 1446 | uchar *vptr = (uchar *) FPUREG_PTR; 1447 | for ( int i = 0; i < 8; ++i, vptr += FPUREG_ENTRY_SIZE ) 1448 | memcpy(vptr, &floats.__fpu_stmm[i], MMX_FPU_REG_DATA_SIZE); 1449 | } 1450 | 1451 | if ( (clsmask & (X86_RC_XMM|X86_RC_YMM)) != 0 ) 1452 | { 1453 | uchar *xptr = XMMREG_PTR; 1454 | memcpy(xptr, &floats.__fpu_xmm[0], (R_MXCSR - R_XMM0) * sizeof(xmm_reg_t)); 1455 | XMMREG_MXCSR = floats.__fpu_mxcsr; 1456 | } 1457 | 1458 | if ( (clsmask & X86_RC_YMM) != 0 1459 | && context_helper.xstate_helpers_loaded() 1460 | && context_helper.pfnSetXStateFeaturesMask(&ctx, XSTATE_MASK_AVX) != FALSE ) 1461 | { 1462 | DWORD xmm_blob_length = 0; 1463 | PM128A Xmm = (PM128A) context_helper.pfnLocateXStateFeature( 1464 | &ctx, 1465 | XSTATE_LEGACY_SSE, 1466 | &xmm_blob_length); 1467 | PM128A Ymm = (PM128A) context_helper.pfnLocateXStateFeature( 1468 | &ctx, 1469 | XSTATE_AVX, 1470 | NULL); 1471 | CASSERT(sizeof(Ymm[0]) == sizeof(xmm_reg_t)); 1472 | const int nxmm_regs = xmm_blob_length / sizeof(Xmm[0]); 1473 | const int nymm_regs = qmin(nxmm_regs, 16); 1474 | memcpy(Ymm, &floats.__fpu_ymmh[0], nymm_regs * sizeof(xmm_reg_t)); 1475 | } 1476 | 1477 | return ti->write_context(clsmask, ctx); 1478 | } 1479 | 1480 | //---------------------------------------------------------------------- 1481 | // return the handle associated with a thread id from the threads list 1482 | HANDLE win32_debmod_t::get_thread_handle(thid_t tid) 1483 | { 1484 | //LOG_FUNC(); 1485 | thread_info_t *tinfo = threads.get(tid); 1486 | return tinfo == NULL ? INVALID_HANDLE_VALUE : tinfo->hThread; 1487 | } 1488 | 1489 | //-------------------------------------------------------------------------- 1490 | bool win32_debmod_t::refresh_hwbpts(void) 1491 | { 1492 | //LOG_FUNC(); 1493 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 1494 | set_hwbpts(p->second.hThread); 1495 | return true; 1496 | } 1497 | 1498 | //-------------------------------------------------------------------------- 1499 | // 1-ok, 0-failed 1500 | int idaapi win32_debmod_t::dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) 1501 | { 1502 | // TODO 1503 | //LOG_FUNC(); 1504 | check_thread(false); 1505 | if ( orig_bytes != NULL ) 1506 | { 1507 | bool ok = false; 1508 | bpts.erase(ea); 1509 | suspend_all_threads(); 1510 | // write the old value only if our bpt is still present 1511 | if ( !has_bpt_at(ea) ) 1512 | { 1513 | if ( !exiting ) 1514 | dmsg("%a: breakpoint vanished from memory\n", ea); 1515 | ok = true; 1516 | } 1517 | else 1518 | { 1519 | ok = _write_memory(ea, orig_bytes, len) == len; 1520 | } 1521 | resume_all_threads(); 1522 | return ok; 1523 | } 1524 | 1525 | // try to delete a page bpt first 1526 | if ( del_page_bpt(ea, type) ) 1527 | return true; 1528 | return del_hwbpt(ea, type); 1529 | } 1530 | 1531 | //-------------------------------------------------------------------------- 1532 | ssize_t win32_debmod_t::_write_memory(eanat_t ea, const void *buffer, size_t size, bool suspend) 1533 | { 1534 | // TODO 1535 | //LOG_FUNC(); 1536 | if ( !may_write(ea) ) 1537 | return -1; 1538 | return access_memory(ea, (void *)buffer, size, true, suspend); 1539 | } 1540 | 1541 | //-------------------------------------------------------------------------- 1542 | void idaapi win32_debmod_t::dbg_term(void) 1543 | { 1544 | //LOG_FUNC(); 1545 | check_thread(true); 1546 | cleanup_hwbpts(); 1547 | cleanup(); 1548 | for ( size_t i = 0; i < pdb_remote_sessions.size(); ++i ) 1549 | close_pdb_remote_session(pdb_remote_sessions[i]); 1550 | inherited::dbg_term(); 1551 | } 1552 | 1553 | //-------------------------------------------------------------------------- 1554 | bool win32_debmod_t::has_bpt_at(ea_t ea) 1555 | { 1556 | // TODO 1557 | //LOG_FUNC(); 1558 | uchar bytes[8]; 1559 | int size = bpt_code.size(); 1560 | return _read_memory(ea, bytes, size) == size 1561 | && memcmp(bytes, bpt_code.begin(), size) == 0; 1562 | } 1563 | 1564 | //-------------------------------------------------------------------------- 1565 | // 2-ok(pagebpt), 1-ok, 0-failed, -2-read failed 1566 | int idaapi win32_debmod_t::dbg_add_bpt( 1567 | bytevec_t *orig_bytes, 1568 | bpttype_t type, 1569 | ea_t ea, 1570 | int len) 1571 | { 1572 | // TODO 1573 | //LOG_FUNC(); 1574 | check_thread(false); 1575 | if ( type == BPT_SOFT ) 1576 | { 1577 | if ( len <= 0 ) 1578 | len = bpt_code.size(); 1579 | if ( orig_bytes != NULL && read_bpt_orgbytes(orig_bytes, ea, len) < 0 ) 1580 | return -2; 1581 | debmod_bpt_t dbpt(ea, len); 1582 | if ( !dbg_read_memory(ea, dbpt.saved, len, NULL) ) 1583 | return -2; 1584 | int size = bpt_code.size(); 1585 | if ( dbg_write_memory(ea, bpt_code.begin(), size, NULL) != size ) 1586 | return 0; 1587 | bpts[ea] = dbpt; 1588 | return 1; 1589 | } 1590 | 1591 | // try, first, to add a real hw breakpoint 1592 | // if it fails, add a memory range type bpt 1593 | // reason: the user may try to insert a 5th 1594 | // correct hw bpt, however, it isn't possible 1595 | // so, instead, we add a page breakpoint 1596 | int ret = 0; 1597 | if ( check_x86_hwbpt(type, ea, len) == BPT_OK ) 1598 | ret = add_hwbpt(type, ea, len); 1599 | 1600 | if ( !ret ) 1601 | ret = dbg_add_page_bpt(type, ea, len); 1602 | return ret; 1603 | } 1604 | 1605 | //-------------------------------------------------------------------------- 1606 | drc_t idaapi win32_debmod_t::dbg_get_memory_info(meminfo_vec_t &ranges, qstring * /*errbuf*/) 1607 | { 1608 | // TODO 1609 | //LOG_FUNC(); 1610 | check_thread(false); 1611 | NODISTURB_ASSERT(in_event != NULL); 1612 | 1613 | images.clear(); 1614 | thread_ranges.clear(); 1615 | class_ranges.clear(); 1616 | for ( threads_t::iterator t=threads.begin(); t != threads.end(); ++t ) 1617 | add_thread_ranges(t->first, thread_ranges, class_ranges); 1618 | 1619 | if ( process_handle != INVALID_HANDLE_VALUE ) 1620 | { 1621 | for ( ea_t ea=0; ea != BADADDR; ) 1622 | { 1623 | memory_info_t meminf; 1624 | ea = get_region_info(ea, &meminf); 1625 | if ( ea != BADADDR && meminf.start_ea != BADADDR ) 1626 | ranges.push_back(meminf); 1627 | } 1628 | enable_page_bpts(true); 1629 | } 1630 | 1631 | if ( same_as_oldmemcfg(ranges) ) 1632 | return DRC_NOCHG; 1633 | 1634 | save_oldmemcfg(ranges); 1635 | return DRC_OK; 1636 | } 1637 | 1638 | //-------------------------------------------------------------------------- 1639 | drc_t idaapi win32_debmod_t::dbg_thread_suspend(thid_t tid) 1640 | { 1641 | //LOG_FUNC(); 1642 | check_thread(false); 1643 | NODISTURB_ASSERT(in_event != NULL); 1644 | int count = SuspendThread(get_thread_handle(tid)); 1645 | if ( count == -1 ) 1646 | deberr("SuspendThread(%08X)", tid); 1647 | 1648 | if ( debug_debugger ) 1649 | debdeb("SuspendThread(%08X) -> %d\n", tid, count); 1650 | 1651 | return count != -1 ? DRC_OK : DRC_FAILED; 1652 | } 1653 | 1654 | //-------------------------------------------------------------------------- 1655 | drc_t idaapi win32_debmod_t::dbg_thread_continue(thid_t tid) 1656 | { 1657 | //LOG_FUNC(); 1658 | check_thread(false); 1659 | NODISTURB_ASSERT(in_event != NULL); 1660 | int count = ResumeThread(get_thread_handle(tid)); 1661 | if ( count == -1 ) 1662 | deberr("ResumeThread(%08X)", tid); 1663 | 1664 | if ( debug_debugger ) 1665 | debdeb("ResumeThread(%08X) -> %d\n", tid, count); 1666 | 1667 | return count != -1 ? DRC_OK : DRC_FAILED; 1668 | } 1669 | 1670 | //-------------------------------------------------------------------------- 1671 | bool thread_info_t::read_context( 1672 | context_holder_t *out, 1673 | int clsmask) 1674 | { 1675 | // if ( (flags & clsmask) == clsmask ) 1676 | // return true; 1677 | 1678 | int ctxflags = calc_ctxflags(clsmask); 1679 | if ( !debmod->context_helper.create_context(out, &ctxflags) ) 1680 | return false; 1681 | 1682 | PCONTEXT ctx = out->ptr; 1683 | #ifndef __X86__ 1684 | if ( is_wow64() && _Wow64GetThreadContext != NULL ) 1685 | { 1686 | WOW64_CONTEXT wow64ctx; 1687 | wow64ctx.ContextFlags = ctxflags_to_wow64(ctxflags); 1688 | if ( !_Wow64GetThreadContext(hThread, &wow64ctx) ) 1689 | return false; 1690 | context_holder_t xstate_ctx; 1691 | if ( (clsmask & X86_RC_YMM) != 0 ) 1692 | { 1693 | int xstate_ctxflags = CONTEXT_XSTATE; 1694 | if ( !debmod->context_helper.create_context(&xstate_ctx, &xstate_ctxflags) ) 1695 | return false; 1696 | if ( !GetThreadContext(hThread, xstate_ctx.ptr) ) 1697 | return false; 1698 | } 1699 | WOW64_CONTEXT_to_CONTEXT( 1700 | ctx, 1701 | wow64ctx, 1702 | clsmask, 1703 | xstate_ctx.ptr, 1704 | debmod->context_helper); 1705 | } 1706 | else 1707 | #endif 1708 | { 1709 | ctx->ContextFlags = ctxflags; 1710 | if ( !GetThreadContext(hThread, ctx) ) 1711 | return false; 1712 | } 1713 | return true; 1714 | } 1715 | 1716 | //-------------------------------------------------------------------------- 1717 | //lint -esym(1764, ctx) could be const ref 1718 | bool thread_info_t::write_context(int clsmask, CONTEXT &ctx) 1719 | { 1720 | #ifndef __X86__ 1721 | if ( is_wow64() && _Wow64SetThreadContext != NULL ) 1722 | { 1723 | context_holder_t xstate_ctx; 1724 | if ( (clsmask & X86_RC_YMM) != 0 ) 1725 | { 1726 | int xstate_ctxflags = CONTEXT_XSTATE; 1727 | if ( !debmod->context_helper.create_context(&xstate_ctx, &xstate_ctxflags) ) 1728 | return false; 1729 | } 1730 | WOW64_CONTEXT wow64ctx; 1731 | CONTEXT_to_WOW64_CONTEXT( 1732 | &wow64ctx, 1733 | ctx, 1734 | xstate_ctx.ptr, 1735 | clsmask, 1736 | debmod->context_helper); 1737 | if ( xstate_ctx.ptr != NULL ) 1738 | { 1739 | if ( SetThreadContext(hThread, xstate_ctx.ptr) == 0 ) 1740 | return false; 1741 | } 1742 | if ( _Wow64SetThreadContext(hThread, &wow64ctx) == 0 ) 1743 | return false; 1744 | return true; 1745 | } 1746 | #else 1747 | qnotused(clsmask); 1748 | #endif 1749 | return SetThreadContext(hThread, &ctx) != 0; 1750 | } 1751 | 1752 | //-------------------------------------------------------------------------- 1753 | drc_t idaapi win32_debmod_t::dbg_prepare_to_pause_process(qstring * /*errbuf*/) 1754 | { 1755 | //LOG_FUNC(); 1756 | check_thread(false); 1757 | bool ok = true; 1758 | win_tool_help_t *wth = get_tool_help(); 1759 | if ( wth->use_debug_break_process() ) // only possible on XP/2K3 or higher 1760 | { 1761 | ok = wth->debug_break_process(process_handle); 1762 | if ( !stop_at_ntdll_bpts ) 1763 | expecting_debug_break = ok; 1764 | } 1765 | else if ( threads.empty() ) 1766 | { 1767 | ok = false; 1768 | } 1769 | else 1770 | { 1771 | suspend_all_threads(); 1772 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 1773 | { 1774 | thread_info_t &ti = p->second; 1775 | context_holder_t ctxh; 1776 | if ( !ti.read_context(&ctxh, X86_RC_GENERAL) ) 1777 | { 1778 | ok = false; 1779 | continue; 1780 | } 1781 | // we have a problem: it is possible that eip points past a temporary breakpoint 1782 | // that will be removed and replaced by the original instruction opcode. 1783 | // if we set a new breakpoint now, it will be at the second byte of the 1784 | // instruction and will lead to a crash. 1785 | eanat_t ip = ctxh.ptr->Eip; 1786 | if ( bpts.find(ip-bpt_code.size()) != bpts.end() ) 1787 | continue; // yes, there is a breakpoint just before us. it was just hit 1788 | // but hopefully not processed yet 1789 | if ( !set_thread_bpt(ti, ip) ) 1790 | ok = false; 1791 | } 1792 | // send WM_NULL to the main thread, hopefully it will wake up the application 1793 | thread_info_t &ti = threads.begin()->second; 1794 | PostThreadMessageA(ti.tid, WM_NULL, 0, 0); 1795 | resume_all_threads(); 1796 | } 1797 | pause_requested = true; 1798 | return ok ? DRC_OK : DRC_FAILED; 1799 | } 1800 | 1801 | //---------------------------------------------------------------------- 1802 | // return the name associated with an existing image in 'images' list 1803 | // containing a particular range 1804 | static const char *get_range_name(const images_t &images, const range_t *range) 1805 | { 1806 | for ( images_t::const_iterator p=images.begin(); p != images.end(); ++p ) 1807 | { 1808 | const image_info_t &img = p->second; 1809 | ea_t ea1 = (ea_t)img.base; 1810 | ea_t ea2 = ea1 + img.imagesize; 1811 | range_t b = range_t(ea1, ea2); 1812 | b.intersect(*range); 1813 | if ( !b.empty() ) 1814 | return img.name.c_str(); 1815 | } 1816 | return NULL; 1817 | } 1818 | 1819 | //-------------------------------------------------------------------------- 1820 | void win32_debmod_t::restore_original_bytes(ea_t ea, bool really_restore) 1821 | { 1822 | //LOG_FUNC(); 1823 | bpt_info_t::iterator p = thread_bpts.find(ea); 1824 | QASSERT(1488, p != thread_bpts.end()); 1825 | if ( --p->second.count == 0 ) 1826 | { 1827 | uchar *obytes = p->second.orig_bytes; 1828 | if ( really_restore ) 1829 | { 1830 | int size = bpt_code.size(); 1831 | if ( _write_memory(ea, obytes, size) != size ) 1832 | INTERR(1489); 1833 | } 1834 | thread_bpts.erase(p); 1835 | } 1836 | } 1837 | 1838 | //-------------------------------------------------------------------------- 1839 | // returns: 0-error,1-ok,2-already had bpt, just increased the counter 1840 | int win32_debmod_t::save_original_bytes(ea_t ea) 1841 | { 1842 | //LOG_FUNC(); 1843 | bpt_info_t::iterator p = thread_bpts.find(ea); 1844 | if ( p == thread_bpts.end() ) 1845 | { 1846 | internal_bpt_info_t ibi; 1847 | ibi.count = 1; 1848 | int size = bpt_code.size(); 1849 | if ( _read_memory(ea, ibi.orig_bytes, size) != size ) 1850 | return 0; 1851 | thread_bpts.insert(std::make_pair(ea, ibi)); 1852 | return 1; 1853 | } 1854 | else 1855 | { 1856 | p->second.count++; 1857 | return 2; 1858 | } 1859 | } 1860 | 1861 | //-------------------------------------------------------------------------- 1862 | bool win32_debmod_t::del_thread_bpt(thread_info_t &ti, ea_t ea) 1863 | { 1864 | // TODO 1865 | //LOG_FUNC(); 1866 | if ( ti.bpt_ea == BADADDR ) 1867 | return false; 1868 | 1869 | if ( ti.bpt_ea == ea ) 1870 | { 1871 | context_holder_t ctxh; 1872 | if ( !ti.read_context(&ctxh, X86_RC_GENERAL) ) 1873 | return false; 1874 | ctxh.ptr->Eip = ti.bpt_ea; // reset EIP 1875 | ctxh.ptr->ContextFlags = CONTEXT_CONTROL; 1876 | if ( !ti.write_context(X86_RC_GENERAL, *ctxh.ptr) ) 1877 | deberr("del_thread_bpt: SetThreadContext"); 1878 | } 1879 | 1880 | // restore old insn if necessary 1881 | restore_original_bytes(ti.bpt_ea); 1882 | ti.bpt_ea = BADADDR; 1883 | return true; 1884 | } 1885 | 1886 | //-------------------------------------------------------------------------- 1887 | // delete all thread breakpoints 1888 | // returns true if a breakpoint at which we stopped was removed 1889 | bool win32_debmod_t::del_thread_bpts(ea_t ea) 1890 | { 1891 | // TODO 1892 | //LOG_FUNC(); 1893 | bool found = false; 1894 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 1895 | found |= del_thread_bpt(p->second, ea); 1896 | return found; 1897 | } 1898 | 1899 | //-------------------------------------------------------------------------- 1900 | bool win32_debmod_t::set_thread_bpt(thread_info_t &ti, ea_t ea) 1901 | { 1902 | //LOG_FUNC(); 1903 | // delete old thread bpt if any existed before 1904 | del_thread_bpt(ti, BADADDR); 1905 | 1906 | ti.bpt_ea = ea; 1907 | int code = save_original_bytes(ti.bpt_ea); 1908 | if ( code ) 1909 | { 1910 | if ( code == 2 ) // already have a bpt? 1911 | return true; // yes, then everything ok 1912 | int size = bpt_code.size(); 1913 | code = _write_memory(ti.bpt_ea, bpt_code.begin(), size); 1914 | if ( code > 0 ) 1915 | { 1916 | if ( code == size ) 1917 | return true; 1918 | // failed to write, forget the original byte 1919 | restore_original_bytes(ti.bpt_ea, false); 1920 | } 1921 | } 1922 | debdeb("%a: set_thread_bpt() failed to pause thread %d\n", ti.bpt_ea, ti.tid); 1923 | ti.bpt_ea = BADADDR; 1924 | return false; 1925 | } 1926 | 1927 | //-------------------------------------------------------------------------- 1928 | void win32_debmod_t::add_thread(const CREATE_THREAD_DEBUG_INFO &thr_info, thid_t tid) 1929 | { 1930 | // TODO 1931 | //LOG_FUNC(); 1932 | wow64_state_t w = check_wow64_process(); 1933 | thread_info_t ti(this, thr_info, tid, w); 1934 | threads.insert(std::make_pair(tid, ti)); 1935 | } 1936 | 1937 | //-------------------------------------------------------------------------- 1938 | gdecode_t win32_debmod_t::get_debug_event(debug_event_t *event, int timeout_ms) 1939 | { 1940 | // TODO 1941 | //LOG_FUNC(); 1942 | check_thread(false); 1943 | 1944 | if (exiting){ 1945 | event->set_exit_code(PROCESS_EXITED, -1); 1946 | exiting = false; 1947 | }else{ 1948 | if ( attach_status == as_none ){ 1949 | msg("PROCESS_STARTED\n"); 1950 | modinfo_t &mi_ps = event->set_modinfo(PROCESS_STARTED); 1951 | mi_ps.name = "1"; 1952 | mi_ps.base = BADADDR; 1953 | mi_ps.size = 0; 1954 | mi_ps.rebase_to = 0x400000; 1955 | binary_to_import = mi_ps; 1956 | attach_status = as_breakpoint; 1957 | }else{ 1958 | msg("PROCESS_SUSPENDED\n"); 1959 | event->set_eid(PROCESS_SUSPENDED); 1960 | } 1961 | } 1962 | event->pid = 1; 1963 | event->tid = 1; 1964 | event->handled = true; 1965 | return GDE_ONE_EVENT; 1966 | /* 1967 | 1968 | 1969 | if ( events.retrieve(event) ) 1970 | return events.empty() ? GDE_ONE_EVENT : GDE_MANY_EVENTS; 1971 | 1972 | DEBUG_EVENT DebugEvent; 1973 | // we have to wait infinitely if we just try to attach to a running process 1974 | if ( attach_status == as_attaching ) 1975 | timeout_ms = INFINITE; 1976 | if ( !WaitForDebugEvent(&DebugEvent, timeout_ms) ) 1977 | { 1978 | // no event occurred 1979 | if ( attach_status == as_detaching ) // if we were requested to detach, 1980 | { // we generate a fake detach event 1981 | event->set_eid(PROCESS_DETACHED); 1982 | return GDE_ONE_EVENT; 1983 | } 1984 | // else, we don't return an event 1985 | return GDE_NO_EVENT; 1986 | } 1987 | 1988 | if ( attach_status == as_attaching ) 1989 | { 1990 | if ( DebugEvent.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT ) 1991 | return GDE_ERROR; 1992 | // fill in starting information for the just attached process (we couldn't do it from CreateProcess() return values !) 1993 | process_path = ""; 1994 | pid = DebugEvent.dwProcessId; 1995 | attach_status = as_breakpoint; 1996 | } 1997 | 1998 | if ( debug_debugger ) 1999 | show_debug_event(DebugEvent); 2000 | 2001 | // ignore events coming from other child processes 2002 | if ( DebugEvent.dwProcessId != pid ) 2003 | { 2004 | debdeb("ignore: pid %x != %x\n", DebugEvent.dwProcessId, pid); 2005 | bool handled = DebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT 2006 | && (DebugEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT 2007 | || DebugEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT); 2008 | 2009 | if ( !ContinueDebugEvent(DebugEvent.dwProcessId, 2010 | DebugEvent.dwThreadId, 2011 | handled ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED) ) 2012 | { 2013 | deberr("ContinueDebugEvent"); 2014 | } 2015 | return GDE_NO_EVENT; 2016 | } 2017 | 2018 | event->pid = DebugEvent.dwProcessId; 2019 | event->tid = DebugEvent.dwThreadId; 2020 | event->handled = true; 2021 | 2022 | gdecode_t gdecode = GDE_ONE_EVENT; 2023 | msg("event: %d\n",DebugEvent.dwDebugEventCode); 2024 | switch ( DebugEvent.dwDebugEventCode ) 2025 | { 2026 | case EXCEPTION_DEBUG_EVENT: 2027 | { 2028 | EXCEPTION_RECORD &er = DebugEvent.u.Exception.ExceptionRecord; 2029 | // remove temporary breakpoints if any 2030 | bool was_thread_bpt = del_thread_bpts(EA_T(er.ExceptionAddress)); 2031 | bool firsttime = DebugEvent.u.Exception.dwFirstChance != 0; 2032 | gdecode = handle_exception(event, er, was_thread_bpt, firsttime); 2033 | } 2034 | break; 2035 | 2036 | case CREATE_THREAD_DEBUG_EVENT: 2037 | { 2038 | // add this thread to our list 2039 | add_thread(DebugEvent.u.CreateThread, event->tid); 2040 | event->set_info(THREAD_STARTED); 2041 | event->ea = EA_T(DebugEvent.u.CreateThread.lpStartAddress); 2042 | // set hardware breakpoints if any 2043 | set_hwbpts(DebugEvent.u.CreateThread.hThread); 2044 | } 2045 | break; 2046 | 2047 | case CREATE_PROCESS_DEBUG_EVENT: 2048 | { 2049 | // save information for later 2050 | cpdi = DebugEvent.u.CreateProcessInfo; 2051 | cpdi.lpBaseOfImage = correct_exe_image_base(cpdi.lpBaseOfImage); 2052 | if ( process_handle != INVALID_HANDLE_VALUE && process_handle != cpdi.hProcess ) 2053 | myCloseHandle(process_handle); // already have an open handle 2054 | process_handle = cpdi.hProcess; 2055 | 2056 | create_start_event(event); 2057 | curproc.insert(std::make_pair(event->modinfo().base, image_info_t(this, event->modinfo()))); 2058 | 2059 | // add record about the main thread into the list 2060 | CREATE_THREAD_DEBUG_INFO ctdi; 2061 | ctdi.hThread = cpdi.hThread; 2062 | ctdi.lpThreadLocalBase = cpdi.lpThreadLocalBase; 2063 | ctdi.lpStartAddress = cpdi.lpStartAddress; 2064 | add_thread(ctdi, DebugEvent.dwThreadId); 2065 | 2066 | // set hardware breakpoints if any 2067 | set_hwbpts(cpdi.hThread); 2068 | 2069 | // test hardware breakpoints: 2070 | // add_hwbpt(HWBPT_WRITE, 0x0012FF68, 4); 2071 | if ( highdlls.empty() && winver.is_DW32() ) // dw32 specific 2072 | { 2073 | HINSTANCE h = GetModuleHandle(kernel32_dll); 2074 | eanat_t addr = eanat_t(h); 2075 | uint32 size = calc_imagesize(addr); 2076 | highdlls.add(addr, size); 2077 | } 2078 | break; 2079 | } 2080 | 2081 | case EXIT_THREAD_DEBUG_EVENT: 2082 | { 2083 | threads.erase(event->tid); 2084 | event->set_exit_code(THREAD_EXITED, DebugEvent.u.ExitThread.dwExitCode); 2085 | // invalidate corresponding handles 2086 | HANDLE h = get_thread_handle(event->tid); 2087 | if ( h == thread_handle ) 2088 | thread_handle = INVALID_HANDLE_VALUE; 2089 | if ( h == cpdi.hThread ) 2090 | cpdi.hThread = INVALID_HANDLE_VALUE; 2091 | break; 2092 | } 2093 | 2094 | case EXIT_PROCESS_DEBUG_EVENT: 2095 | event->set_exit_code(PROCESS_EXITED, DebugEvent.u.ExitProcess.dwExitCode); 2096 | exiting = true; 2097 | break; 2098 | 2099 | case LOAD_DLL_DEBUG_EVENT: 2100 | { 2101 | const LOAD_DLL_DEBUG_INFO &dil = DebugEvent.u.LoadDll; 2102 | eanat_t addr = eanat_t(dil.lpBaseOfDll); 2103 | modinfo_t &mi_ll = event->set_modinfo(LIB_LOADED); 2104 | event->ea = addr; 2105 | mi_ll.base = event->ea; 2106 | mi_ll.rebase_to = BADADDR; // this must be determined locally - see common_local.cpp 2107 | 2108 | char full_name[MAXSTR]; 2109 | full_name[0] = '\0'; 2110 | bool ok = get_filename_for(full_name, 2111 | sizeof(full_name), 2112 | eanat_t(dil.lpImageName), 2113 | dil.fUnicode != 0, 2114 | addr); 2115 | // Win 7 may send a bogus DLL load event for the main module 2116 | // ignore event if this module has already been mapped 2117 | if ( !ok || module_present(full_name) ) 2118 | { 2119 | debdeb("%p: bogus DLL load event, skippping\n", addr); 2120 | goto SILENTLY_RESUME; 2121 | } 2122 | mi_ll.name = full_name; 2123 | uint32 size = calc_imagesize(addr); 2124 | mi_ll.size = size; 2125 | 2126 | // does the address fit into ea_t? 2127 | HANDLE ntdll_handle = dil.hFile; 2128 | if ( highdlls.add_high_module(addr, size, ntdll_handle) ) 2129 | { 2130 | debdeb("%p: 64bit DLL loaded into high addresses has been detected\n", 2131 | addr); 2132 | goto SILENTLY_RESUME; 2133 | } 2134 | 2135 | // we defer the import of the dll until the moment when ida stops 2136 | // at a debug event. we do so to avoid unnecessary imports because 2137 | // the dll might get unloaded before ida stops. 2138 | image_info_t di(this, DebugEvent.u.LoadDll, size, full_name); 2139 | add_dll(di); 2140 | // determine the attach breakpoint if needed 2141 | size_t max_ntdlls = check_wow64_process() == WOW64_YES ? 2 : 1; 2142 | if ( highdlls.count_ntdlls() < max_ntdlls ) 2143 | { 2144 | if ( is_ntdll_name(full_name) ) 2145 | highdlls.add_ntdll(addr, size); 2146 | if ( attach_status == as_none && !stop_at_ntdll_bpts ) 2147 | expecting_debug_break = highdlls.count_ntdlls(); 2148 | } 2149 | break; 2150 | } 2151 | 2152 | SILENTLY_RESUME: 2153 | // do not report this event to ida 2154 | event->handled = true; 2155 | dbg_continue_after_event(event); 2156 | return GDE_NO_EVENT; 2157 | 2158 | case UNLOAD_DLL_DEBUG_EVENT: 2159 | event->set_info(LIB_UNLOADED); 2160 | { 2161 | eanat_t addr = eanat_t(DebugEvent.u.UnloadDll.lpBaseOfDll); 2162 | range_t range(addr, addr+MEMORY_PAGE_SIZE); // we assume DLL image is at least a PAGE size 2163 | const char *name = get_range_name(dlls, &range); 2164 | if ( name != NULL ) 2165 | event->info() = name; 2166 | else 2167 | event->info().clear(); 2168 | 2169 | // remove ntdll from the list 2170 | HANDLE ntdll_handle; 2171 | if ( highdlls.del_high_module(&ntdll_handle, addr) ) 2172 | { 2173 | myCloseHandle(ntdll_handle); 2174 | goto SILENTLY_RESUME; 2175 | } 2176 | 2177 | // close the associated DLL handle 2178 | images_t::iterator p = dlls.find(addr); 2179 | if ( p != dlls.end() ) 2180 | { 2181 | myCloseHandle(p->second.dll_info.hFile); 2182 | // Remove it from the list of dlls to import 2183 | // (in the case it was never imported) 2184 | dlls_to_import.erase(p->first); 2185 | dlls.erase(p); 2186 | } 2187 | else 2188 | { 2189 | debdeb("Could not find dll to unload (base=%a)\n", EA_T(DebugEvent.u.UnloadDll.lpBaseOfDll)); 2190 | } 2191 | } 2192 | break; 2193 | 2194 | case OUTPUT_DEBUG_STRING_EVENT: 2195 | { 2196 | char buf[MAXSTR]; 2197 | get_debug_string(DebugEvent, buf, sizeof(buf)); 2198 | event->set_info(INFORMATION) = buf; 2199 | } 2200 | break; 2201 | 2202 | case RIP_EVENT: 2203 | debdeb("RIP_EVENT (system debugging error)"); 2204 | break; 2205 | 2206 | default: 2207 | debdeb("UNKNOWN_EVENT %d", DebugEvent.dwDebugEventCode); 2208 | event->handled = false; // don't handle it 2209 | break; 2210 | } 2211 | 2212 | if ( gdecode > GDE_NO_EVENT && attach_status == as_breakpoint && event->eid() == EXCEPTION ) 2213 | { // exception while attaching. apparently things went wrong 2214 | // pretend that we attached successfully 2215 | events.enqueue(*event, IN_BACK); 2216 | create_attach_event(event, true); 2217 | attach_status = as_none; 2218 | } 2219 | return gdecode; 2220 | */ 2221 | 2222 | } 2223 | 2224 | //-------------------------------------------------------------------------- 2225 | gdecode_t idaapi win32_debmod_t::dbg_get_debug_event(debug_event_t *event, int timeout_ms) 2226 | { 2227 | // TODO 2228 | //LOG_FUNC(); 2229 | check_thread(false); 2230 | gdecode_t gdecode = get_debug_event(event, timeout_ms); 2231 | if ( gdecode >= GDE_ONE_EVENT ) 2232 | { 2233 | last_event = *event; 2234 | in_event = &last_event; 2235 | pause_requested = false; 2236 | } 2237 | return gdecode; 2238 | } 2239 | 2240 | 2241 | //-------------------------------------------------------------------------- 2242 | bool win32_debmod_t::get_debug_string(const DEBUG_EVENT &ev, char *buf, size_t bufsize) 2243 | { 2244 | //LOG_FUNC(); 2245 | buf[0] = '\0'; 2246 | size_t nullsize = ev.u.DebugString.fUnicode ? sizeof(wchar_t) : 1; 2247 | size_t msize = qmin(ev.u.DebugString.nDebugStringLength, bufsize-nullsize); 2248 | ea_t ea = EA_T(ev.u.DebugString.lpDebugStringData); 2249 | ssize_t rsize = _read_memory(ea, buf, msize); 2250 | if ( rsize == msize ) 2251 | { 2252 | buf[rsize] = '\0'; 2253 | if ( ev.u.DebugString.fUnicode ) 2254 | { 2255 | *(wchar_t*)(buf + rsize) = 0; 2256 | utf16_to_utf8(buf, bufsize, (LPCWSTR)buf); 2257 | } 2258 | return true; 2259 | } 2260 | return false; 2261 | } 2262 | 2263 | //-------------------------------------------------------------------------- 2264 | void win32_debmod_t::cleanup() 2265 | { 2266 | // TODO 2267 | //LOG_FUNC(); 2268 | myCloseHandle(redirin_handle); 2269 | myCloseHandle(redirout_handle); 2270 | myCloseHandle(thread_handle); 2271 | myCloseHandle(process_handle); 2272 | myCloseHandle(cpdi.hFile); 2273 | 2274 | // Close handles of remaining DLLs 2275 | for ( images_t::iterator p=dlls.begin(); p != dlls.end(); ++p ) 2276 | myCloseHandle(p->second.dll_info.hFile); 2277 | 2278 | pid = -1; 2279 | highdlls.clear(); 2280 | stop_at_ntdll_bpts = qgetenv("IDA_SYSTEMBREAKPOINT"); 2281 | expecting_debug_break = 0; 2282 | in_event = NULL; 2283 | memset(&cpdi, 0, sizeof(cpdi)); 2284 | cpdi.hFile = INVALID_HANDLE_VALUE; 2285 | cpdi.hProcess = INVALID_HANDLE_VALUE; 2286 | cpdi.hThread = INVALID_HANDLE_VALUE; 2287 | attach_status = as_none; 2288 | attach_evid = INVALID_HANDLE_VALUE; 2289 | 2290 | old_ranges.clear(); 2291 | threads.clear(); 2292 | thread_bpts.clear(); 2293 | bpts.clear(); 2294 | curproc.clear(); 2295 | dlls.clear(); 2296 | dlls_to_import.clear(); 2297 | images.clear(); 2298 | thread_ranges.clear(); 2299 | class_ranges.clear(); 2300 | context_helper.clear(); 2301 | inherited::cleanup(); 2302 | } 2303 | 2304 | //-------------------------------------------------------------------------- 2305 | void win32_debmod_t::_term_reg_ctx(void) 2306 | { 2307 | // TODO 2308 | //LOG_FUNC(); 2309 | if ( reg_ctx != nullptr ) 2310 | { 2311 | delete reg_ctx; 2312 | idaregs.clear(); 2313 | } 2314 | reg_ctx = nullptr; 2315 | } 2316 | 2317 | #define DRVBUFSIZE 512 2318 | 2319 | //-------------------------------------------------------------------------- 2320 | // Translate path with device name to drive letters. 2321 | // e.g. \Device\HarddiskVolume4\Windows\System32\ntdll.dll -> C:\Windows\System32\ntdll.dll 2322 | static void translate_nt_path(qstring *out, LPCWSTR pszFilename) 2323 | { 2324 | WCHAR szTemp[DRVBUFSIZE]; 2325 | 2326 | // get a list of all drive letters 2327 | if ( GetLogicalDriveStringsW(qnumber(szTemp) - 1, szTemp) ) 2328 | { 2329 | WCHAR szName[MAX_PATH]; 2330 | WCHAR szDrive[3] = L" :"; 2331 | BOOL bFound = FALSE; 2332 | WCHAR *p = szTemp; 2333 | 2334 | do 2335 | { 2336 | // Copy the drive letter to the template string 2337 | *szDrive = *p; 2338 | 2339 | // Look up device name for this drive 2340 | DWORD uNameLen = QueryDosDeviceW(szDrive, szName, qnumber(szName) - 1); 2341 | if ( uNameLen != 0 ) 2342 | { 2343 | // for some reason return value is 2 chars longer, so get the actual length 2344 | uNameLen = wcslen(szName); 2345 | // do we have a match at the start of filename? 2346 | bFound = _wcsnicmp(pszFilename, szName, uNameLen) == 0 2347 | && pszFilename[uNameLen] == L'\\'; 2348 | 2349 | if ( bFound ) 2350 | { 2351 | // Reconstruct filename 2352 | // by replacing device path with DOS path (drive) 2353 | qstring path; 2354 | utf16_utf8(out, szDrive); 2355 | utf16_utf8(&path, pszFilename + uNameLen); 2356 | out->append(path); 2357 | return; 2358 | } 2359 | } 2360 | 2361 | // Go to the next NULL character. 2362 | while ( *p++ ) 2363 | ; 2364 | } 2365 | while ( !bFound && *p ); // end of string 2366 | } 2367 | } 2368 | 2369 | //-------------------------------------------------------------------------- 2370 | bool win32_debmod_t::get_filename_for( 2371 | char *buf, 2372 | size_t bufsize, 2373 | eanat_t image_name_ea, 2374 | bool use_unicode, 2375 | eanat_t image_base) 2376 | { 2377 | // TODO 2378 | //LOG_FUNC(); 2379 | buf[0] = '\0'; 2380 | // if we have address of file name in the process image from the debug API, try to use it 2381 | // remark: depending on the OS, NTDLL.DLL can return an empty string or only the DLL name! 2382 | if ( image_name_ea != 0 ) 2383 | { 2384 | if ( get_filename_from_process(image_name_ea, use_unicode, buf, bufsize) ) 2385 | return true; 2386 | } 2387 | 2388 | // various fallbacks 2389 | // first try GetMappedFileName 2390 | if ( _GetMappedFileName != NULL ) 2391 | { 2392 | wchar16_t tbuf[MAXSTR]; 2393 | HMODULE hmod = (HMODULE)(size_t)image_base; 2394 | if ( _GetMappedFileName(process_handle, hmod, tbuf, qnumber(tbuf)) ) 2395 | { 2396 | qstring tmp; 2397 | translate_nt_path(&tmp, tbuf); 2398 | qstrncpy(buf, tmp.c_str(), bufsize); 2399 | return true; 2400 | } 2401 | } 2402 | 2403 | // then try GetModuleFileNameEx 2404 | if ( _GetModuleFileNameEx != NULL ) 2405 | { 2406 | wchar16_t tbuf[MAXSTR]; 2407 | HMODULE hmod = (HMODULE)(size_t)image_base; 2408 | if ( _GetModuleFileNameEx(process_handle, hmod, tbuf, qnumber(tbuf)) ) 2409 | { 2410 | qstring tmp; 2411 | utf16_utf8(&tmp, tbuf); 2412 | qstrncpy(buf, tmp.c_str(), bufsize); 2413 | return true; 2414 | } 2415 | } 2416 | 2417 | // last: we try to get DLL name by looking at the export name from 2418 | // the export directory in PE image in debugged process. 2419 | // this is the least reliable way since this string may not match the actual dll filename 2420 | get_pe_export_name_from_process(image_base, buf, bufsize); 2421 | 2422 | // for dlls without path, try to find it 2423 | find_full_path(buf, bufsize, process_path.c_str()); 2424 | 2425 | // convert possible short path to long path 2426 | qffblk64_t fb; 2427 | if ( qfindfirst(buf, &fb, 0) == 0 ) 2428 | { 2429 | char *fptr = qbasename(buf); 2430 | qstrncpy(fptr, fb.ff_name, bufsize-(fptr-buf)); 2431 | } 2432 | return buf[0] != '\0'; 2433 | } 2434 | 2435 | //-------------------------------------------------------------------------- 2436 | drc_t idaapi win32_debmod_t::dbg_detach_process() 2437 | { 2438 | //LOG_FUNC(); 2439 | check_thread(false); 2440 | if ( in_event != NULL ) 2441 | dbg_continue_after_event(in_event); 2442 | BOOL ret = get_tool_help()->debug_detach_process(pid); 2443 | if ( ret ) 2444 | { 2445 | attach_status = as_detaching; 2446 | exiting = true; 2447 | } 2448 | return ret ? DRC_OK : DRC_FAILED; 2449 | } 2450 | 2451 | //-------------------------------------------------------------------------- 2452 | void idaapi win32_debmod_t::dbg_set_debugging(bool _debug_debugger) 2453 | { 2454 | // TODO 2455 | //LOG_FUNC(); 2456 | debug_debugger = _debug_debugger; 2457 | debug_debugger = 1; 2458 | } 2459 | 2460 | //-------------------------------------------------------------------------- 2461 | drc_t idaapi win32_debmod_t::dbg_init(uint32_t *flags2, qstring * /*errbuf*/) 2462 | { 2463 | // TODO 2464 | //LOG_FUNC(); 2465 | check_thread(true); 2466 | 2467 | cleanup(); 2468 | cleanup_hwbpts(); 2469 | 2470 | if ( flags2 != nullptr ) 2471 | *flags2 = g_code; 2472 | 2473 | return DRC_OK; 2474 | } 2475 | 2476 | //-------------------------------------------------------------------------- 2477 | image_info_t::image_info_t(win32_debmod_t *ses) 2478 | : sess(ses), base(BADADDR), imagesize(0) 2479 | { 2480 | memset(&dll_info, 0, sizeof(dll_info)); 2481 | } 2482 | 2483 | image_info_t::image_info_t( 2484 | win32_debmod_t *ses, 2485 | ea_t _base, 2486 | uint32 _imagesize, 2487 | const qstring &_name) 2488 | : sess(ses), base(_base), imagesize(_imagesize), name(_name) 2489 | { 2490 | memset(&dll_info, 0, sizeof(dll_info)); 2491 | } 2492 | 2493 | image_info_t::image_info_t( 2494 | win32_debmod_t *ses, 2495 | const LOAD_DLL_DEBUG_INFO &i, 2496 | uint32 _imagesize, 2497 | const char *_name) 2498 | : sess(ses), name(_name), dll_info(i) 2499 | { 2500 | base = EA_T(i.lpBaseOfDll); 2501 | imagesize = _imagesize; 2502 | } 2503 | 2504 | image_info_t::image_info_t(win32_debmod_t *ses, const modinfo_t &m) 2505 | : sess(ses), base(m.base), imagesize(m.size), name(m.name) 2506 | { 2507 | memset(&dll_info, 0, sizeof(dll_info)); 2508 | } 2509 | 2510 | //-------------------------------------------------------------------------- 2511 | // get (path+)name from debugged process 2512 | // lpFileName - pointer to pointer to the file name 2513 | // use_unicode - true if the filename is in unicode 2514 | bool win32_debmod_t::get_filename_from_process( 2515 | eanat_t name_ea, 2516 | bool use_unicode, 2517 | char *buf, 2518 | size_t bufsize) 2519 | { 2520 | // TODO 2521 | //LOG_FUNC(); 2522 | buf[0] = '\0'; 2523 | if ( name_ea == 0 ) 2524 | return false; 2525 | eanat_t dll_addr; 2526 | if ( _read_memory(name_ea, &dll_addr, sizeof(dll_addr)) != sizeof(dll_addr) ) 2527 | return false; 2528 | if ( dll_addr == NULL ) 2529 | return false; 2530 | name_ea = dll_addr; 2531 | if ( _read_memory(name_ea, buf, bufsize) != bufsize ) 2532 | return false; 2533 | if ( use_unicode ) 2534 | utf16_to_utf8(buf, bufsize, (LPCWSTR)buf); 2535 | return true; 2536 | } 2537 | 2538 | //-------------------------------------------------------------------------- 2539 | ea_t win32_debmod_t::get_region_info(ea_t ea, memory_info_t *mi) 2540 | { 2541 | // TODO 2542 | //LOG_FUNC(); 2543 | // okay to keep static, they won't change between clients 2544 | static DWORD_PTR totalVirtual = 0; 2545 | static DWORD granularity = 0; 2546 | 2547 | if ( totalVirtual == 0 ) 2548 | { 2549 | SYSTEM_INFO si; 2550 | GetSystemInfo(&si); 2551 | granularity = si.dwAllocationGranularity; 2552 | totalVirtual = (DWORD_PTR)si.lpMaximumApplicationAddress; 2553 | } 2554 | 2555 | void *addr = (void *)(size_t)ea; 2556 | MEMORY_BASIC_INFORMATION meminfo; 2557 | while ( !VirtualQueryEx(process_handle, // handle of process 2558 | addr, // address of region 2559 | &meminfo, // address of information buffer 2560 | sizeof(meminfo)) ) // size of buffer 2561 | { 2562 | // On Windows CE VirtualQueryEx can fail when called with addr == 0, 2563 | // so try to call it again with the next page (and end loop after 2d 2564 | // iteration to prevent scanning of huge number of pages) 2565 | // It's possible VirtualQueryEx fails on Windows CE not only for zero 2566 | // address: perhaps we shouldn't limit the number of iterations and return 2567 | // to using of a separate variable 'first' (as in win32_debmod.cpp#34) 2568 | if ( ea != 0 || ea >= totalVirtual ) 2569 | return BADADDR; 2570 | // try to find next valid page 2571 | ea += granularity; 2572 | addr = (void *)(size_t)ea; 2573 | } 2574 | 2575 | eanat_t startea = (eanat_t)meminfo.BaseAddress; 2576 | eanat_t endea = startea + meminfo.RegionSize; 2577 | if ( endea <= startea // overflow/empty? 2578 | #if !defined(__X86__) && !defined(__EA64__) 2579 | || endea >= BADADDR // crossed 4GB boundary 2580 | #endif 2581 | ) 2582 | { 2583 | if ( endea == startea ) 2584 | { 2585 | // ignore empty sections ... 2586 | mi->start_ea = BADADDR; 2587 | mi->end_ea = BADADDR; 2588 | return endea + 1; 2589 | } 2590 | // signal end of enumeration 2591 | endea = BADADDR; 2592 | } 2593 | 2594 | // debdeb("VirtualQueryEx(%a): base = %a, end = %a, protect=0x%x, allocprotect=0x%x, state=0x%x\n", ea, startea, endea, meminfo.Protect, meminfo.AllocationProtect, meminfo.State); 2595 | 2596 | // hide the page bpts in this memory region from ida 2597 | uint32 prot = meminfo.Protect; 2598 | if ( mask_page_bpts(startea, endea, &prot) ) 2599 | { 2600 | debdeb(" masked protect=0x%x\n", prot); 2601 | meminfo.Protect = prot; 2602 | } 2603 | 2604 | if ( (meminfo.State & (MEM_FREE|MEM_RESERVE)) == MEM_FREE // if the range isn't interesting for/accessible by IDA 2605 | || (meminfo.Protect & PAGE_NOACCESS) != 0 ) 2606 | { // we simply return an invalid range, and a pointer to the next (eventual) range 2607 | mi->start_ea = BADADDR; 2608 | mi->end_ea = BADADDR; 2609 | return endea; 2610 | } 2611 | 2612 | mi->start_ea = startea; 2613 | mi->end_ea = endea; 2614 | #ifdef __EA64__ 2615 | // we may be running a 32bit process in wow64 with ida64 2616 | mi->bitness = check_wow64_process() > 0 ? 1 : 2; 2617 | #else 2618 | mi->bitness = 1; // 32bit 2619 | #endif 2620 | 2621 | // convert Windows protection modes to IDA protection modes 2622 | mi->perm = win_prot_to_ida_perm(meminfo.Protect); 2623 | 2624 | // try to associate a segment name to the memory range 2625 | const char *ptr; 2626 | if ( (ptr=get_range_name(curproc, mi)) != NULL // first try with the current process 2627 | || (ptr=get_range_name(dlls, mi)) != NULL // then try in DLLs 2628 | || (ptr=get_range_name(images, mi)) != NULL // then try in previous images ranges 2629 | || (ptr=get_range_name(thread_ranges, mi)) != NULL ) // and finally in thread ranges 2630 | { 2631 | // return the filename without the file path 2632 | mi->name = qbasename(ptr); 2633 | } 2634 | else 2635 | { 2636 | char buf[MAXSTR]; 2637 | buf[0] = '\0'; 2638 | // check for a mapped filename 2639 | get_filename_for(buf, sizeof(buf), 0, false, mi->start_ea); 2640 | if ( buf[0] != '\0' ) 2641 | { 2642 | mi->name = qbasename(buf); 2643 | } 2644 | // if we found nothing, check if the segment is a PE file header, 2645 | // and we try to locate a name in it 2646 | else if ( get_pe_export_name_from_process(mi->start_ea, buf, sizeof(buf)) ) 2647 | { // we insert it in the image ranges list 2648 | uint32 size = calc_imagesize(mi->start_ea); 2649 | image_info_t ii(this, mi->start_ea, size, buf); 2650 | images.insert(std::make_pair(ii.base, ii)); 2651 | mi->name = buf; 2652 | } 2653 | } 2654 | 2655 | // try to associate a segment class name to the memory range 2656 | mi->sclass = get_range_name(class_ranges, mi); 2657 | return endea; 2658 | } 2659 | 2660 | //-------------------------------------------------------------------------- 2661 | drc_t idaapi win32_debmod_t::dbg_attach_process(pid_t _pid, int event_id, int /*flags*/, qstring * /*errbuf*/) 2662 | { 2663 | //LOG_FUNC(); 2664 | check_thread(false); 2665 | #ifndef __EA64__ 2666 | int addrsize = get_process_addrsize(_pid); 2667 | if ( addrsize > 4 ) 2668 | { 2669 | dwarning("AUTOHIDE NONE\nPlease use ida64 to debug 64-bit applications"); 2670 | SetLastError(ERROR_NOT_SUPPORTED); 2671 | return DRC_FAILED; 2672 | } 2673 | #endif 2674 | if ( !DebugActiveProcess(_pid) ) 2675 | { 2676 | deberr("DebugActiveProcess %08lX", _pid); 2677 | return DRC_FAILED; 2678 | } 2679 | 2680 | if ( !handle_process_start(_pid) ) 2681 | return DRC_FAILED; 2682 | 2683 | attach_status = as_attaching; 2684 | attach_evid = (HANDLE)(INT_PTR)(event_id); 2685 | exiting = false; 2686 | return DRC_OK; 2687 | } 2688 | 2689 | //-------------------------------------------------------------------------- 2690 | drc_t idaapi win32_debmod_t::dbg_start_process( 2691 | const char *path, 2692 | const char *args, 2693 | const char *startdir, 2694 | int flags, 2695 | const char *input_path, 2696 | uint32 input_file_crc32, 2697 | qstring * /*errbuf*/) 2698 | { 2699 | // TODO 2700 | //LOG_FUNC(); 2701 | /* 2702 | check_thread(false); 2703 | // input file specified in the database does not exist 2704 | if ( input_path[0] != '\0' && !qfileexist(input_path) ) 2705 | { 2706 | dwarning("AUTOHIDE NONE\nInput file is missing: %s", input_path); 2707 | return DRC_NOFILE; 2708 | } 2709 | 2710 | input_file_path = input_path; 2711 | is_dll = (flags & DBG_PROC_IS_DLL) != 0; 2712 | 2713 | char fullpath[QMAXPATH]; 2714 | if ( !qfileexist(path) ) 2715 | { 2716 | if ( qisabspath(path) || !search_path(fullpath, sizeof(fullpath), path, false) ) 2717 | { 2718 | dwarning("AUTOHIDE NONE\nCannot find application file '%s'", path); 2719 | return DRC_NETERR; 2720 | } 2721 | path = fullpath; 2722 | } 2723 | 2724 | drc_t drc = DRC_OK; 2725 | if ( !check_input_file_crc32(input_file_crc32) ) 2726 | drc = DRC_CRC; 2727 | 2728 | exiting = false; 2729 | 2730 | // Build a full command line 2731 | qstring args_buffer; // this vector must survive until create_process() 2732 | if ( args != NULL && args[0] != '\0' ) 2733 | { 2734 | args_buffer += '"'; 2735 | args_buffer += path; 2736 | args_buffer += '"'; 2737 | args_buffer += ' '; 2738 | args_buffer += args; 2739 | args = args_buffer.c_str(); 2740 | } 2741 | 2742 | PROCESS_INFORMATION ProcessInformation; 2743 | bool is_gui = (flags & DBG_PROC_IS_GUI) != 0; 2744 | bool hide_window = (flags & DBG_HIDE_WINDOW) != 0; 2745 | if ( !create_process(path, args, startdir, is_gui, hide_window, &ProcessInformation) ) 2746 | return DRC_FAILED; 2747 | 2748 | pid = ProcessInformation.dwProcessId; 2749 | process_handle = ProcessInformation.hProcess; 2750 | thread_handle = ProcessInformation.hThread; 2751 | process_path = path; 2752 | 2753 | if ( !handle_process_start(pid) ) 2754 | return DRC_NETERR; 2755 | 2756 | return drc; 2757 | */ 2758 | #ifdef __EA64__ 2759 | is64 = 1; 2760 | #else 2761 | is64 = 0; 2762 | #endif 2763 | term_reg_ctx(); 2764 | init_reg_ctx(); 2765 | return DRC_OK; 2766 | } 2767 | 2768 | //-------------------------------------------------------------------------- 2769 | //lint -esym(1762,win32_debmod_t::myCloseHandle) could be made const 2770 | bool win32_debmod_t::myCloseHandle(HANDLE &h) 2771 | { 2772 | // TODO 2773 | //LOG_FUNC(); 2774 | bool ok = true; 2775 | if ( h != INVALID_HANDLE_VALUE && h != NULL ) 2776 | { 2777 | DWORD code; 2778 | __try 2779 | { 2780 | ok = CloseHandle(h) != 0; 2781 | if ( !ok ) 2782 | deberr("CloseHandle(%08X)", h); 2783 | } 2784 | __except ( code=GetExceptionCode() ) 2785 | { 2786 | debdeb("CloseHandle(%08X) exception code %08X\n", h, code); 2787 | ok = false; 2788 | } 2789 | h = INVALID_HANDLE_VALUE; 2790 | } 2791 | return ok; 2792 | } 2793 | 2794 | //-------------------------------------------------------------------------- 2795 | void win32_debmod_t::install_callgate_workaround(thread_info_t *ti, const debug_event_t *event) 2796 | { 2797 | //LOG_FUNC(); 2798 | // add a breakpoint after the call statement 2799 | ea_t bpt = event->ea + 7; 2800 | ti->callgate_ea = bpt; 2801 | if ( !set_thread_bpt(*ti, bpt) ) 2802 | INTERR(637); // how can it be? 2803 | } 2804 | 2805 | //-------------------------------------------------------------------------- 2806 | // we do not use 'firsttime' argument anymore. we could use it to distinguish 2807 | // the first chance and the second chance but it is more logical to 2808 | // behave consistently. 2809 | gdecode_t win32_debmod_t::handle_exception( 2810 | debug_event_t *event, 2811 | const EXCEPTION_RECORD &er, 2812 | bool was_thread_bpt, 2813 | bool /*firsttime*/) 2814 | { 2815 | // TODO 2816 | //LOG_FUNC(); 2817 | int code = er.ExceptionCode; 2818 | const exception_info_t *ei = find_exception(code); 2819 | 2820 | eanat_t addr = eanat_t(er.ExceptionAddress); 2821 | excinfo_t &exc = event->set_exception(); 2822 | event->ea = addr; 2823 | exc.code = code; 2824 | exc.can_cont = (er.ExceptionFlags == 0); 2825 | exc.ea = BADADDR; 2826 | event->handled = false; 2827 | 2828 | if ( exiting && ei == NULL ) 2829 | { 2830 | event->set_exit_code(PROCESS_EXITED, -1); 2831 | return GDE_ONE_EVENT; 2832 | } 2833 | 2834 | bool suspend = true; 2835 | 2836 | // we don't expect callgate breakpoints anymore 2837 | ea_t was_callgate_ea = BADADDR; 2838 | thread_info_t *ti = threads.get(event->tid); 2839 | if ( ti != NULL ) 2840 | { 2841 | was_callgate_ea = ti->callgate_ea; 2842 | ti->callgate_ea = BADADDR; 2843 | } 2844 | 2845 | if ( ei != NULL ) 2846 | { 2847 | event->handled = ei->handle(); 2848 | // if the user asked to suspend the process, do not resume 2849 | if ( !was_thread_bpt ) 2850 | suspend = ei->break_on() || pause_requested; 2851 | } 2852 | if ( !suspend ) 2853 | suspend = should_suspend_at_exception(event, ei); 2854 | exc.info.qclear(); 2855 | int elc_flags = 0; 2856 | switch ( uint32(code) ) 2857 | { 2858 | case EXCEPTION_BREAKPOINT: 2859 | case STATUS_WX86_BREAKPOINT: 2860 | if ( was_thread_bpt ) 2861 | { 2862 | QASSERT(638, ti != NULL); 2863 | 2864 | // is installed the workaround for the 'freely running after syscall' problem? 2865 | if ( was_callgate_ea == event->ea ) 2866 | event->set_eid(STEP); 2867 | else 2868 | event->set_eid(PROCESS_SUSPENDED); 2869 | break; 2870 | } 2871 | if ( attach_status == as_breakpoint ) // the process was successfully suspended after an attachement 2872 | { 2873 | create_attach_event(event, true); 2874 | break; 2875 | } 2876 | if ( expecting_debug_break > 0 2877 | && highdlls.has(addr) 2878 | && get_kernel_bpt_ea(event->ea, event->tid) == BADADDR ) // not user-defined bpt 2879 | { 2880 | --expecting_debug_break; 2881 | debdeb("%a: resuming after DbgBreakPoint(), expecting bpts: %d\n", event->ea, expecting_debug_break); 2882 | event->handled = true; 2883 | dbg_continue_after_event(event); 2884 | return GDE_NO_EVENT; 2885 | } 2886 | // is this a breakpoint set by ida? 2887 | { 2888 | ea_t kea = get_kernel_bpt_ea(event->ea, event->tid); 2889 | if ( kea != BADADDR ) 2890 | { 2891 | bptaddr_t &bpta = event->set_bpt(); 2892 | bpta.hea = BADADDR; // no referenced address (only for hardware breakpoint) 2893 | bpta.kea = kea == event->ea ? BADADDR : kea; 2894 | event->handled = true; 2895 | } 2896 | } 2897 | break; 2898 | case EXCEPTION_SINGLE_STEP: 2899 | case STATUS_WX86_SINGLE_STEP: 2900 | { 2901 | bool is_stepping = ti != NULL && ti->is_tracing(); 2902 | // if this happened because of a hardware breakpoint 2903 | // find out which one caused it 2904 | if ( !check_for_hwbpt(event, is_stepping) ) 2905 | { 2906 | // if we have not asked for single step, do not convert it to STEP 2907 | if ( is_stepping ) 2908 | { 2909 | event->set_eid(STEP); // Single-step breakpoint 2910 | event->handled = true; 2911 | ti->clr_tracing(); 2912 | break; 2913 | } 2914 | } 2915 | } 2916 | break; 2917 | case EXCEPTION_ACCESS_VIOLATION: 2918 | { 2919 | ea_t exc_ea = EA_T(er.ExceptionInformation[1]); // virtual address of the inaccessible data. 2920 | exc.ea = exc_ea; 2921 | // is this a page bpt? 2922 | page_bpts_t::iterator p = find_page_bpt(exc_ea); 2923 | if ( p == page_bpts.end() ) 2924 | { 2925 | exc_ea = event->ea; 2926 | p = find_page_bpt(exc_ea); 2927 | } 2928 | if ( p != page_bpts.end() ) 2929 | { 2930 | // since on access violation the system does not update anything 2931 | // there is no need to reset eip when handling lowcnd below. 2932 | elc_flags |= ELC_KEEP_EIP; 2933 | ea_t exc_eip = EA_T(er.ExceptionAddress); 2934 | if ( !should_fire_page_bpt(p, exc_ea, er.ExceptionInformation[0], 2935 | exc_eip, dep_policy) ) 2936 | { // Silently step over the page breakpoint 2937 | if ( ti != NULL && ti->is_tracing() ) 2938 | elc_flags |= ELC_KEEP_SUSP; 2939 | lowcnd_t lc; 2940 | const pagebpt_data_t &bpt = p->second; 2941 | lc.ea = bpt.ea; 2942 | lc.type = bpt.type; 2943 | lc.size = bpt.user_len; 2944 | if ( !handling_lowcnds.has(bpt.ea) 2945 | && handle_lowcnd(&lc, event, elc_flags) ) 2946 | { 2947 | if ( (elc_flags & ELC_KEEP_SUSP) != 0 ) 2948 | { // if we were tracing, report a STEP event 2949 | event->set_eid(STEP); 2950 | event->handled = true; 2951 | ti->clr_tracing(); 2952 | return GDE_ONE_EVENT; 2953 | } 2954 | return GDE_NO_EVENT; 2955 | } 2956 | // failed to step over, return the exception 2957 | } 2958 | else 2959 | { 2960 | bptaddr_t &bpta = event->set_bpt(); 2961 | bpta.hea = p->second.ea; 2962 | bpta.kea = BADADDR; 2963 | event->handled = true; 2964 | break; 2965 | } 2966 | } 2967 | if ( ei != NULL && event->eid() == EXCEPTION ) 2968 | { 2969 | int einfo = er.ExceptionInformation[0]; 2970 | const char *verb = einfo == EXCEPTION_EXECUTE_FAULT ? "executed" 2971 | : einfo == EXCEPTION_WRITE_FAULT ? "written" 2972 | : "read"; 2973 | exc.info.sprnt(ei->desc.c_str(), event->ea, exc.ea, verb); 2974 | } 2975 | } 2976 | break; 2977 | #define EXCEPTION_BCC_FATAL 0xEEFFACE 2978 | #define EXCEPTION_BCC_NORMAL 0xEEDFAE6 2979 | case EXCEPTION_BCC_FATAL: 2980 | case EXCEPTION_BCC_NORMAL: 2981 | if ( er.NumberParameters == 5 2982 | && er.ExceptionInformation[0] == 2 // these numbers are highly hypothetic 2983 | && er.ExceptionInformation[1] == 3 ) 2984 | { 2985 | EXCEPTION_RECORD r2; 2986 | if ( dbg_read_memory(er.ExceptionInformation[3], &r2, sizeof(r2), NULL) == sizeof(r2) ) 2987 | return handle_exception(event, r2, false, false); 2988 | } 2989 | break; 2990 | #define MS_VC_EXCEPTION 0x406D1388L 2991 | case MS_VC_EXCEPTION: 2992 | // SetThreadName 2993 | // https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx 2994 | if ( er.ExceptionInformation[0] == 0x1000 2995 | && er.ExceptionInformation[3] == 0x00 ) 2996 | { 2997 | qstring name; 2998 | name.resize(MAXSTR); 2999 | ea_t nameaddr = er.ExceptionInformation[1]; 3000 | if ( dbg_read_memory(nameaddr, name.begin(), name.length(), NULL) > 0 ) 3001 | { 3002 | thid_t tid = er.ExceptionInformation[2]; 3003 | msg("Thread %d is named '%s'\n", tid, name.c_str()); 3004 | thread_info_t *tin = threads.get(tid); 3005 | if ( tin != NULL ) 3006 | { 3007 | tin->name = name.c_str(); 3008 | tin->set_new_name(); 3009 | } 3010 | event->handled = true; 3011 | } 3012 | } 3013 | break; 3014 | } 3015 | if ( !pause_requested && evaluate_and_handle_lowcnd(event, elc_flags) ) 3016 | return GDE_NO_EVENT; 3017 | 3018 | if ( event->eid() == EXCEPTION ) 3019 | { 3020 | if ( ei == NULL ) 3021 | { 3022 | exc.info.sprnt("unknown exception code %X", code); 3023 | } 3024 | else if ( exc.info.empty() ) 3025 | { 3026 | exc.info.sprnt(ei->desc.c_str(), event->ea, 3027 | ea_t(er.ExceptionInformation[0]), 3028 | ea_t(er.ExceptionInformation[1])); 3029 | } 3030 | if ( !suspend ) 3031 | { 3032 | log_exception(event, ei); 3033 | // if a single step was scheduled by the user 3034 | if ( ti != NULL && ti->is_tracing() ) 3035 | { 3036 | clear_tbit(*ti); 3037 | if ( event->handled ) 3038 | { 3039 | // since we mask the exception, we generate a STEP event 3040 | event->set_eid(STEP); 3041 | return GDE_ONE_EVENT; // got an event 3042 | } 3043 | } 3044 | dbg_continue_after_event(event); 3045 | return GDE_NO_EVENT; 3046 | } 3047 | } 3048 | return GDE_ONE_EVENT; 3049 | } 3050 | 3051 | //-------------------------------------------------------------------------- 3052 | bool win32_debmod_t::check_for_hwbpt(debug_event_t *event, bool is_stepping) 3053 | { 3054 | //LOG_FUNC(); 3055 | ea_t ea = is_hwbpt_triggered(event->tid, is_stepping); 3056 | if ( ea != BADADDR ) 3057 | { 3058 | bptaddr_t &addr = event->set_bpt(); 3059 | addr.hea = ea; 3060 | addr.kea = BADADDR; 3061 | event->handled = true; 3062 | return true; 3063 | } 3064 | return false; 3065 | } 3066 | 3067 | //-------------------------------------------------------------------------- 3068 | void win32_debmod_t::create_attach_event(debug_event_t *event, bool attached) 3069 | { 3070 | //LOG_FUNC(); 3071 | event->set_modinfo(PROCESS_ATTACHED); 3072 | event->handled = true; 3073 | if ( attached ) 3074 | attach_status = as_attached; 3075 | else 3076 | attach_status = as_attaching; 3077 | if ( attach_evid != INVALID_HANDLE_VALUE ) 3078 | { 3079 | SetEvent(attach_evid); 3080 | attach_evid = INVALID_HANDLE_VALUE; 3081 | } 3082 | modinfo_t &mi_ps = event->modinfo(); 3083 | get_debugged_module_info(&mi_ps); 3084 | 3085 | binary_to_import = mi_ps; 3086 | } 3087 | 3088 | //-------------------------------------------------------------------------- 3089 | void win32_debmod_t::create_start_event(debug_event_t *event) 3090 | { 3091 | // TODO 3092 | //LOG_FUNC(); 3093 | modinfo_t &mi_ps = event->set_modinfo(PROCESS_STARTED); 3094 | // ea_t base = EA_T(cpdi.lpBaseOfImage); 3095 | 3096 | // process_snapshot_t psnap(get_tool_help()); 3097 | // PROCESSENTRY32 pe32; 3098 | // for ( bool ok = psnap.first(TH32CS_SNAPNOHEAPS, &pe32); ok; ok = psnap.next(&pe32) ) 3099 | // { 3100 | // if ( pe32.th32ProcessID == event->pid ) 3101 | // { 3102 | // char exefile[QMAXPATH]; 3103 | // tchar_utf8(exefile, pe32.szExeFile, sizeof(exefile)); 3104 | // if ( !qisabspath(exefile) ) 3105 | // { 3106 | // char abspath[QMAXPATH]; 3107 | // get_filename_for(abspath, 3108 | // sizeof(abspath), 3109 | // /*image_name_ea=*/ 0, 3110 | // /*use_unicode=*/ false, // irrelevant 3111 | // base); 3112 | // if ( abspath[0] != '\0' ) 3113 | // qstrncpy(exefile, abspath, sizeof(exefile)); 3114 | // } 3115 | // if ( process_path.empty() || qisabspath(exefile) ) 3116 | // process_path = exefile; 3117 | // break; 3118 | // } 3119 | // } 3120 | mi_ps.name = ""; 3121 | mi_ps.base = BADADDR; 3122 | mi_ps.size = 0; 3123 | //mi_ps.rebase_to = 0x400000; 3124 | mi_ps.rebase_to = BADADDR; // this must be determined locally - see common_local.cpp 3125 | 3126 | binary_to_import = mi_ps; 3127 | } 3128 | 3129 | //-------------------------------------------------------------------------- 3130 | ea_t win32_debmod_t::get_kernel_bpt_ea(ea_t ea, thid_t tid) 3131 | { 3132 | // TODO 3133 | //LOG_FUNC(); 3134 | if ( is_ida_bpt(ea, tid) ) 3135 | return ea; 3136 | return BADADDR; 3137 | } 3138 | 3139 | 3140 | ssize_t idaapi win32_debmod_t::dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring * /*errbuf*/) 3141 | { 3142 | // TODO 3143 | //LOG_FUNC(); 3144 | check_thread(false); 3145 | return _write_memory(ea, buffer, size, true); 3146 | } 3147 | 3148 | //-------------------------------------------------------------------------- 3149 | drc_t idaapi win32_debmod_t::dbg_thread_get_sreg_base( 3150 | ea_t *pea, 3151 | thid_t tid, 3152 | int sreg_value, 3153 | qstring * /*errbuf*/) 3154 | { 3155 | //LOG_FUNC(); 3156 | check_thread(false); 3157 | NODISTURB_ASSERT(in_event != NULL); 3158 | HANDLE h = get_thread_handle(tid); 3159 | if ( h == INVALID_HANDLE_VALUE ) 3160 | return DRC_FAILED; 3161 | 3162 | #ifndef __X86__ 3163 | 3164 | thread_info_t *ti = threads.get(tid); 3165 | context_holder_t ctxh; 3166 | if ( ti != NULL && ti->read_context(&ctxh, X86_RC_SEGMENTS) ) 3167 | { 3168 | // is this a TLS base register? (FS for wow64 and GS for x64) 3169 | if ( sreg_value == ctxh.ptr->SegGs && !ti->is_wow64() 3170 | || sreg_value == ctxh.ptr->SegFs && ti->is_wow64() ) 3171 | { 3172 | // lpThreadLocalBase is the native (X64) TEB, or GS base 3173 | if ( sreg_value == ctxh.ptr->SegGs ) 3174 | *pea = EA_T(ti->lpThreadLocalBase); 3175 | else 3176 | { 3177 | // fs base is the WoW64 TEB 3178 | // pointer to it is the first field in the native TEB 3179 | LPVOID tib32; 3180 | if ( _read_memory(EA_T(ti->lpThreadLocalBase), &tib32, sizeof(tib32)) != sizeof(tib32) ) 3181 | return DRC_FAILED; 3182 | *pea = EA_T(tib32); 3183 | } 3184 | return DRC_OK; 3185 | } 3186 | else if ( ti->is_wow64() ) 3187 | { 3188 | WOW64_LDT_ENTRY se; 3189 | if ( !_Wow64GetThreadSelectorEntry(h, sreg_value, &se) ) 3190 | { 3191 | if ( GetLastError() == ERROR_NOT_SUPPORTED ) 3192 | { 3193 | // in x64 all selectors except fs/gs are 0-based 3194 | *pea = 0; 3195 | return DRC_OK; 3196 | } 3197 | deberr("GetThreadSelectorEntry"); 3198 | return DRC_FAILED; 3199 | } 3200 | *pea = (se.HighWord.Bytes.BaseHi << 24) 3201 | | (se.HighWord.Bytes.BaseMid << 16) 3202 | | se.BaseLow; 3203 | return DRC_OK; 3204 | } 3205 | } 3206 | #endif // __X64__ 3207 | // the below code works for non-x64 3208 | LDT_ENTRY se; 3209 | if ( !GetThreadSelectorEntry(h, sreg_value, &se) ) 3210 | { 3211 | if ( GetLastError() == ERROR_NOT_SUPPORTED ) 3212 | { 3213 | *pea = 0; 3214 | return DRC_OK; 3215 | } 3216 | deberr("GetThreadSelectorEntry"); 3217 | return DRC_FAILED; 3218 | } 3219 | 3220 | *pea = (se.HighWord.Bytes.BaseHi << 24) 3221 | | (se.HighWord.Bytes.BaseMid << 16) 3222 | | se.BaseLow; 3223 | return DRC_OK; 3224 | } 3225 | 3226 | //------------------------------------------------------------------------- 3227 | drc_t idaapi win32_debmod_t::dbg_write_register( 3228 | thid_t tid, 3229 | int reg_idx, 3230 | const regval_t *value, 3231 | qstring * /*errbuf*/) 3232 | { 3233 | // TODO 3234 | //LOG_FUNC(); 3235 | check_thread(false); 3236 | if ( value == NULL ) 3237 | return DRC_FAILED; 3238 | 3239 | NODISTURB_ASSERT(in_event != NULL); 3240 | 3241 | reg_ctx->setup(tid); 3242 | reg_ctx->setup_reg(reg_idx); 3243 | context_holder_t ctxh; 3244 | if ( !reg_ctx->load(&ctxh) ) 3245 | return DRC_FAILED; 3246 | 3247 | if ( !reg_ctx->patch(reg_idx, value) ) 3248 | return DRC_FAILED; 3249 | 3250 | if ( !reg_ctx->store(ctxh) ) 3251 | return DRC_FAILED; 3252 | 3253 | return DRC_OK; 3254 | } 3255 | 3256 | //-------------------------------------------------------------------------- 3257 | bool idaapi win32_debmod_t::write_registers( 3258 | thid_t tid, 3259 | int start, 3260 | int count, 3261 | const regval_t *values) 3262 | { 3263 | //LOG_FUNC(); 3264 | if ( values == nullptr ) 3265 | return false; 3266 | 3267 | reg_ctx->setup(tid); 3268 | for ( size_t i = 0; i < count; i++ ) 3269 | reg_ctx->setup_reg(start + i); 3270 | context_holder_t ctxh; 3271 | if ( !reg_ctx->load(&ctxh) ) 3272 | return false; 3273 | 3274 | for ( size_t i = 0; i < count; i++, values++ ) 3275 | if ( !reg_ctx->patch(start + i, values) ) 3276 | return false; 3277 | 3278 | if ( !reg_ctx->store(ctxh) ) 3279 | return false; 3280 | 3281 | return true; 3282 | } 3283 | 3284 | //-------------------------------------------------------------------------- 3285 | drc_t idaapi win32_debmod_t::dbg_read_registers( 3286 | thid_t tid, 3287 | int clsmask, 3288 | regval_t *values, 3289 | qstring * /*errbuf*/) 3290 | { 3291 | //LOG_FUNC(); 3292 | check_thread(false); 3293 | if ( values == nullptr ) 3294 | return DRC_FAILED; 3295 | /* 3296 | reg_ctx->setup(tid, clsmask); 3297 | context_holder_t ctxh; 3298 | if ( !reg_ctx->load(&ctxh) ) 3299 | return DRC_FAILED; 3300 | 3301 | reg_ctx->read_all(values); 3302 | */ 3303 | Json::Value sendroot,recvroot; 3304 | Json::FastWriter writer; 3305 | Json::Reader reader; 3306 | sendroot["func"] = "dbg_read_registers"; 3307 | const std::string json_file = writer.write(sendroot); 3308 | connect_server((char *)json_file.c_str(), json_file.length(), recvbuf, &recvlen); 3309 | reader.parse(std::string(recvbuf,recvlen), recvroot); 3310 | int sz = recvroot["ret"].size(); 3311 | for (int i=0; iEFlags & EFLAGS_TRAP_FLAG) != (set_tbit << 8) ) //lint !e647 possible truncation before conversion from 'int' to 'unsigned long' 3330 | { 3331 | QASSERT(30117, (ctxh.ptr->ContextFlags & CONTEXT_CONTROL) != 0); 3332 | ctxh.ptr->EFlags |= EFLAGS_TRAP_FLAG; 3333 | ctxh.ptr->ContextFlags = CONTEXT_CONTROL; 3334 | ok = write_context(X86_RC_GENERAL, *ctxh.ptr); 3335 | if ( ok ) 3336 | setflag(flags, THR_TRACING, set_tbit); 3337 | else 3338 | debmod->deberr("%d: SetThreadContext failed", tid); 3339 | } 3340 | return ok; 3341 | } 3342 | 3343 | //-------------------------------------------------------------------------- 3344 | drc_t idaapi win32_debmod_t::dbg_set_resume_mode(thid_t tid, resume_mode_t resmod) 3345 | { 3346 | // TODO 3347 | //LOG_FUNC(); 3348 | if ( resmod != RESMOD_INTO ) 3349 | return DRC_FAILED; // not supported 3350 | 3351 | check_thread(false); 3352 | NODISTURB_ASSERT(in_event != NULL); 3353 | thread_info_t *ti = threads.get(tid); 3354 | if ( ti == NULL ) 3355 | return DRC_FAILED; 3356 | 3357 | bool ok = ti->toggle_tbit(true); 3358 | if ( !ok ) 3359 | deberr("%d: (set_step) SetThreadContext failed", tid); 3360 | return ok ? DRC_OK : DRC_FAILED; 3361 | } 3362 | 3363 | //-------------------------------------------------------------------------- 3364 | bool win32_debmod_t::clear_tbit(thread_info_t &ti) 3365 | { 3366 | //LOG_FUNC(); 3367 | NODISTURB_ASSERT(in_event != NULL); 3368 | bool ok = ti.toggle_tbit(false); 3369 | if ( !ok ) 3370 | deberr("%d: (clr_step) SetThreadContext failed", ti.tid); 3371 | return ok; 3372 | } 3373 | 3374 | //-------------------------------------------------------------------------- 3375 | drc_t idaapi win32_debmod_t::dbg_continue_after_event(const debug_event_t *event) 3376 | { 3377 | // TODO 3378 | //LOG_FUNC(); 3379 | /* 3380 | check_thread(false); 3381 | NODISTURB_ASSERT(in_event != NULL || exiting); 3382 | 3383 | if ( event == NULL ) 3384 | return DRC_FAILED; 3385 | 3386 | if ( events.empty() ) 3387 | { 3388 | bool done = false; 3389 | if ( !done ) //-V547 '!done' is always true 3390 | { 3391 | // check if we need to install the workaround for single stepping over callgates 3392 | thread_info_t *ti = threads.get(event->tid); 3393 | if ( ti != NULL && ti->is_tracing() ) 3394 | { 3395 | if ( check_for_call_large(event, process_handle) ) 3396 | install_callgate_workaround(ti, event); 3397 | } 3398 | 3399 | int flag = event->handled ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED; 3400 | if ( !ContinueDebugEvent(event->pid, event->tid, flag) ) 3401 | { 3402 | deberr("ContinueDebugEvent"); 3403 | return DRC_FAILED; 3404 | } 3405 | debdeb("ContinueDebugEvent: handled=%s\n", event->handled ? "yes" : "no"); 3406 | if ( event->eid() == PROCESS_EXITED ) 3407 | { 3408 | // from WaitForDebugEvent help page: 3409 | // If the system previously reported an EXIT_PROCESS_DEBUG_EVENT debugging event, 3410 | // the system closes the handles to the process and thread when the debugger calls the ContinueDebugEvent function. 3411 | // => we don't close these handles to avoid error messages 3412 | cpdi.hProcess = INVALID_HANDLE_VALUE; 3413 | cpdi.hThread = INVALID_HANDLE_VALUE; 3414 | process_handle= INVALID_HANDLE_VALUE; 3415 | thread_handle = INVALID_HANDLE_VALUE; 3416 | cleanup(); 3417 | } 3418 | } 3419 | } 3420 | in_event = NULL; 3421 | */ 3422 | if (exiting) { 3423 | cleanup(); 3424 | } 3425 | return DRC_OK; 3426 | } 3427 | 3428 | //-------------------------------------------------------------------------- 3429 | drc_t idaapi win32_debmod_t::dbg_exit_process(qstring * /*errbuf*/) 3430 | { 3431 | //LOG_FUNC(); 3432 | /* 3433 | check_thread(false); 3434 | // WindowsCE sometimes reports failure but terminates the application. 3435 | // We ignore the return value. 3436 | bool check_termination_code = prepare_to_stop_process(in_event, threads); 3437 | bool terminated = TerminateProcess(process_handle, -1) != 0; 3438 | if ( !terminated && check_termination_code ) 3439 | { 3440 | deberr("TerminateProcess"); 3441 | return DRC_FAILED; 3442 | } 3443 | exiting = true; 3444 | 3445 | if ( in_event != NULL && dbg_continue_after_event(in_event) != DRC_OK ) 3446 | { 3447 | deberr("continue_after_event"); 3448 | return DRC_FAILED; 3449 | } 3450 | */ 3451 | exiting = true; 3452 | dbg_continue_after_event(in_event); 3453 | return DRC_OK; 3454 | } 3455 | 3456 | 3457 | //-------------------------------------------------------------------------- 3458 | void win32_debmod_t::show_exception_record(const EXCEPTION_RECORD &er, int level) 3459 | { 3460 | //LOG_FUNC(); 3461 | char name[MAXSTR]; 3462 | get_exception_name(er.ExceptionCode, name, sizeof(name)); 3463 | if ( level > 0 ) 3464 | dmsg("%*c", level, ' '); 3465 | dmsg("%s: fl=%X adr=%a #prm=%d\n", 3466 | name, 3467 | er.ExceptionFlags, 3468 | EA_T(er.ExceptionAddress), 3469 | er.NumberParameters); 3470 | if ( er.NumberParameters > 0 ) 3471 | { 3472 | dmsg("%*c", level+2, ' '); 3473 | int n = qmin(er.NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS); 3474 | for ( int i=0; i < n; i++ ) 3475 | dmsg("%s0x%a", i == 0 ? "" : " ", ea_t(er.ExceptionInformation[i])); 3476 | dmsg("\n"); 3477 | } 3478 | if ( er.ExceptionRecord != NULL ) 3479 | show_exception_record(*er.ExceptionRecord, level+2); 3480 | } 3481 | 3482 | //-------------------------------------------------------------------------- 3483 | void win32_debmod_t::show_debug_event(const DEBUG_EVENT &ev) 3484 | { 3485 | //LOG_FUNC(); 3486 | if ( !debug_debugger ) 3487 | return; 3488 | dmsg("[%u %d] ", ev.dwProcessId, ev.dwThreadId); 3489 | switch ( ev.dwDebugEventCode ) 3490 | { 3491 | case EXCEPTION_DEBUG_EVENT: 3492 | { 3493 | const EXCEPTION_RECORD &er = ev.u.Exception.ExceptionRecord; 3494 | dmsg("EXCEPTION: ea=%p first: %d", // no \n intentionally 3495 | er.ExceptionAddress, ev.u.Exception.dwFirstChance); 3496 | show_exception_record(er); 3497 | } 3498 | break; 3499 | 3500 | case CREATE_THREAD_DEBUG_EVENT: 3501 | dmsg("CREATE_THREAD: hThread=%X LocalBase=%p Entry=%p\n", 3502 | ev.u.CreateThread.hThread, 3503 | ev.u.CreateThread.lpThreadLocalBase, 3504 | ev.u.CreateThread.lpStartAddress); 3505 | break; 3506 | 3507 | case CREATE_PROCESS_DEBUG_EVENT: 3508 | { 3509 | const CREATE_PROCESS_DEBUG_INFO &cpinf = ev.u.CreateProcessInfo; 3510 | char path[QMAXPATH]; 3511 | if ( process_handle == INVALID_HANDLE_VALUE ) 3512 | process_handle = cpinf.hProcess; 3513 | get_filename_for( 3514 | path, 3515 | sizeof(path), 3516 | eanat_t(cpinf.lpImageName), 3517 | cpinf.fUnicode != 0, 3518 | eanat_t(cpinf.lpBaseOfImage)); 3519 | dmsg("CREATE_PROCESS: hFile=%X hProcess=%X hThread=%X " 3520 | "base=%p\n dbgoff=%X dbgsiz=%X tlbase=%p start=%p name=%p '%s' \n", 3521 | cpinf.hFile, cpinf.hProcess, cpinf.hThread, cpinf.lpBaseOfImage, 3522 | cpinf.dwDebugInfoFileOffset, cpinf.nDebugInfoSize, cpinf.lpThreadLocalBase, 3523 | cpinf.lpStartAddress, cpinf.lpImageName, path); 3524 | } 3525 | break; 3526 | 3527 | case EXIT_THREAD_DEBUG_EVENT: 3528 | dmsg("EXIT_THREAD: code=%d\n", ev.u.ExitThread.dwExitCode); 3529 | break; 3530 | 3531 | case EXIT_PROCESS_DEBUG_EVENT: 3532 | dmsg("EXIT_PROCESS: code=%d\n", ev.u.ExitProcess.dwExitCode); 3533 | break; 3534 | 3535 | case LOAD_DLL_DEBUG_EVENT: 3536 | { 3537 | char path[QMAXPATH]; 3538 | const LOAD_DLL_DEBUG_INFO &di = ev.u.LoadDll; 3539 | get_filename_for( 3540 | path, 3541 | sizeof(path), 3542 | eanat_t(di.lpImageName), 3543 | di.fUnicode != 0, 3544 | eanat_t(di.lpBaseOfDll)); 3545 | dmsg("LOAD_DLL: h=%X base=%p dbgoff=%X dbgsiz=%X name=%X '%s'\n", 3546 | di.hFile, di.lpBaseOfDll, di.dwDebugInfoFileOffset, di.nDebugInfoSize, 3547 | di.lpImageName, path); 3548 | } 3549 | break; 3550 | 3551 | case UNLOAD_DLL_DEBUG_EVENT: 3552 | dmsg("UNLOAD_DLL: base=%p\n", ev.u.UnloadDll.lpBaseOfDll); 3553 | break; 3554 | 3555 | case OUTPUT_DEBUG_STRING_EVENT: 3556 | { 3557 | char buf[MAXSTR]; 3558 | get_debug_string(ev, buf, sizeof(buf)); 3559 | dmsg("OUTPUT_DEBUG_STRING: str=\"%s\"\n", buf); 3560 | } 3561 | break; 3562 | 3563 | case RIP_EVENT: 3564 | dmsg("RIP_EVENT (system debugging error)\n"); 3565 | break; 3566 | 3567 | default: 3568 | dmsg("UNKNOWN_DEBUG_EVENT %d\n", ev.dwDebugEventCode); 3569 | break; 3570 | } 3571 | } 3572 | 3573 | //-------------------------------------------------------------------------- 3574 | int win32_debmod_t::dbg_freeze_threads_except(thid_t tid) 3575 | { 3576 | //LOG_FUNC(); 3577 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 3578 | if ( p->first != tid ) 3579 | _sure_suspend_thread(p->second, true); 3580 | return 1; 3581 | } 3582 | 3583 | //-------------------------------------------------------------------------- 3584 | int win32_debmod_t::dbg_thaw_threads_except(thid_t tid) 3585 | { 3586 | //LOG_FUNC(); 3587 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 3588 | if ( p->first != tid ) 3589 | _sure_resume_thread(p->second, true); 3590 | return 1; 3591 | } 3592 | 3593 | //-------------------------------------------------------------------------- 3594 | // if we have to do something as soon as we noticed the connection 3595 | // broke, this is the correct place 3596 | bool idaapi win32_debmod_t::dbg_prepare_broken_connection(void) 3597 | { 3598 | //LOG_FUNC(); 3599 | broken_connection = true; 3600 | bool ret = false; 3601 | if ( restore_broken_breakpoints() ) 3602 | { 3603 | // create the required event for synchronization; we use it 3604 | // to notify when the process was successfully detached 3605 | broken_event_handle = CreateEvent(NULL, false, false, NULL); 3606 | 3607 | if ( broken_event_handle != NULL ) 3608 | { 3609 | int code = WAIT_TIMEOUT; 3610 | while ( code == WAIT_TIMEOUT ) 3611 | code = WaitForSingleObject(broken_event_handle, 100); 3612 | 3613 | if ( code == WAIT_OBJECT_0 ) 3614 | { 3615 | suspend_running_threads(_suspended_threads); 3616 | if ( dbg_detach_process() == DRC_OK ) 3617 | SetEvent(broken_event_handle); 3618 | } 3619 | } 3620 | } 3621 | 3622 | return ret; 3623 | } 3624 | 3625 | //-------------------------------------------------------------------------- 3626 | // Continuing from a broken connection in win32 debugger consist in the 3627 | // following step (if we're talking about a single threaded server): 3628 | // 3629 | // 1 - Notify the other thread that we want to reuse that connection 3630 | // 2 - Wait for the previous thread to notify that finished his work 3631 | // 3 - Reattach to the process and reopen thread's handles as, for a 3632 | // reason, the handles we have are invalid (why?). 3633 | // 4 - Resume the threads we suspended before. 3634 | // 3635 | bool idaapi win32_debmod_t::dbg_continue_broken_connection(pid_t _pid) 3636 | { 3637 | //LOG_FUNC(); 3638 | debmod_t::dbg_continue_broken_connection(_pid); 3639 | 3640 | QASSERT(676, broken_event_handle != NULL); 3641 | 3642 | // notify the broken thread we want to reuse the connection 3643 | SetEvent(broken_event_handle); 3644 | 3645 | // and wait for the notification for a maximum of 15 seconds 3646 | // as we don't want to wait forever (INFINITE) because the 3647 | // other thread may fail 3648 | int code = WaitForSingleObject(broken_event_handle, 15000); 3649 | if ( code != WAIT_OBJECT_0 ) 3650 | { 3651 | msg("Error restoring broken connection"); 3652 | return false; 3653 | } 3654 | 3655 | if ( dbg_attach_process(_pid, -1, 0, NULL) == DRC_OK && reopen_threads() ) 3656 | { 3657 | resume_suspended_threads(_suspended_threads); 3658 | return true; 3659 | } 3660 | return false; 3661 | } 3662 | 3663 | //-------------------------------------------------------------------------- 3664 | bool win32_debmod_t::reopen_threads(void) 3665 | { 3666 | //LOG_FUNC(); 3667 | if ( _OpenThread == NULL ) 3668 | return false; 3669 | 3670 | for ( threads_t::iterator p=threads.begin(); p != threads.end(); ++p ) 3671 | { 3672 | HANDLE hThread; 3673 | hThread = _OpenThread(THREAD_ALL_ACCESS, true, p->second.tid); 3674 | if ( hThread != NULL ) 3675 | p->second.hThread = hThread; 3676 | else 3677 | deberr("OpenThread"); 3678 | p->second.suspend_count = get_thread_suspend_count(hThread); 3679 | } 3680 | return true; 3681 | } 3682 | 3683 | //-------------------------------------------------------------------------- 3684 | static bool enable_privilege(LPCTSTR privilege, bool enable); 3685 | static bool g_subsys_inited = false; 3686 | static bool g_got_debpriv = false; 3687 | 3688 | bool init_subsystem() 3689 | { 3690 | if ( g_subsys_inited ) 3691 | return true; 3692 | 3693 | if ( !win32_debmod_t::winver.ok() ) 3694 | return false; 3695 | 3696 | win_tool_help_t *wth = win32_debmod_t::get_tool_help(); 3697 | if ( wth->ok() ) 3698 | g_code |= DBG_HAS_GET_PROCESSES; 3699 | 3700 | // DebugActiveProcessStop() is only available on XP/2K3 3701 | if ( wth->use_debug_detach_process() ) 3702 | g_code |= DBG_HAS_DETACH_PROCESS; 3703 | 3704 | g_got_debpriv = enable_privilege(SE_DEBUG_NAME, true); 3705 | if ( !g_got_debpriv ) 3706 | msg("Cannot set debug privilege: %s.\n" 3707 | "Debugging of processes owned by another account won't be possible.\n", 3708 | winerr(GetLastError())); 3709 | 3710 | win32_debmod_t::reuse_broken_connections = true; 3711 | init_win32_subsystem(); 3712 | 3713 | HINSTANCE h = GetModuleHandle(kernel32_dll); 3714 | *(FARPROC*)&_OpenThread = GetProcAddress(h, TEXT("OpenThread")); 3715 | *(FARPROC*)&_GetThreadDescription = GetProcAddress(h, TEXT("GetThreadDescription")); 3716 | 3717 | #ifndef __X86__ 3718 | *(FARPROC*)&_Wow64GetThreadContext = GetProcAddress(h, TEXT("Wow64GetThreadContext")); 3719 | *(FARPROC*)&_Wow64SetThreadContext = GetProcAddress(h, TEXT("Wow64SetThreadContext")); 3720 | *(FARPROC*)&_Wow64GetThreadSelectorEntry = GetProcAddress(h, TEXT("Wow64GetThreadSelectorEntry")); 3721 | #endif 3722 | 3723 | g_subsys_inited = g_code != 0; 3724 | return g_subsys_inited; 3725 | } 3726 | 3727 | //-------------------------------------------------------------------------- 3728 | bool term_subsystem() 3729 | { 3730 | if ( !g_subsys_inited ) 3731 | return true; 3732 | 3733 | g_subsys_inited = false; 3734 | 3735 | if ( g_got_debpriv ) 3736 | { 3737 | enable_privilege(SE_DEBUG_NAME, false); 3738 | g_got_debpriv = false; 3739 | } 3740 | 3741 | term_win32_subsystem(); 3742 | return true; 3743 | } 3744 | 3745 | //-------------------------------------------------------------------------- 3746 | debmod_t *create_debug_session(void *) 3747 | { 3748 | return new win32_debmod_t(); 3749 | } 3750 | 3751 | //-------------------------------------------------------------------------- 3752 | // 3753 | // DEBUG PRIVILEGE 3754 | // 3755 | //-------------------------------------------------------------------------- 3756 | // dynamic linking information for Advapi functions 3757 | static HMODULE hAdvapi32 = NULL; 3758 | // function prototypes 3759 | typedef BOOL (WINAPI *OpenProcessToken_t)( 3760 | HANDLE ProcessHandle, 3761 | DWORD DesiredAccess, 3762 | PHANDLE TokenHandle); 3763 | typedef BOOL (WINAPI *LookupPrivilegeValue_t)( 3764 | LPCTSTR lpSystemName, 3765 | LPCTSTR lpName, 3766 | PLUID lpLuid); 3767 | typedef BOOL (WINAPI *AdjustTokenPrivileges_t)( 3768 | HANDLE TokenHandle, 3769 | BOOL DisableAllPrivileges, 3770 | PTOKEN_PRIVILEGES NewState, 3771 | DWORD BufferLength, 3772 | PTOKEN_PRIVILEGES PreviousState, 3773 | PDWORD ReturnLength); 3774 | 3775 | // Function pointers 3776 | static OpenProcessToken_t _OpenProcessToken = NULL; 3777 | static LookupPrivilegeValue_t _LookupPrivilegeValue = NULL; 3778 | static AdjustTokenPrivileges_t _AdjustTokenPrivileges = NULL; 3779 | 3780 | //-------------------------------------------------------------------------- 3781 | static void term_advapi32(void) 3782 | { 3783 | if ( hAdvapi32 != NULL ) 3784 | { 3785 | DWORD code = GetLastError(); 3786 | FreeLibrary(hAdvapi32); 3787 | SetLastError(code); 3788 | hAdvapi32 = NULL; 3789 | } 3790 | } 3791 | 3792 | //-------------------------------------------------------------------------- 3793 | static bool init_advapi32(void) 3794 | { 3795 | // load the library 3796 | hAdvapi32 = LoadLibrary(TEXT("advapi32.dll")); 3797 | if ( hAdvapi32 == NULL ) 3798 | return false; 3799 | 3800 | // find the needed functions 3801 | *(FARPROC*)&_OpenProcessToken = GetProcAddress(hAdvapi32, TEXT("OpenProcessToken")); 3802 | *(FARPROC*)&_LookupPrivilegeValue = GetProcAddress(hAdvapi32, TEXT(LookupPrivilegeValue_Name)); 3803 | *(FARPROC*)&_AdjustTokenPrivileges = GetProcAddress(hAdvapi32, TEXT("AdjustTokenPrivileges")); 3804 | 3805 | bool ok = _OpenProcessToken != NULL 3806 | && _LookupPrivilegeValue != NULL 3807 | && _AdjustTokenPrivileges != NULL; 3808 | if ( !ok ) 3809 | term_advapi32(); 3810 | return ok; 3811 | } 3812 | 3813 | 3814 | //-------------------------------------------------------------------------- 3815 | // based on code from: 3816 | // http://support.microsoft.com/support/kb/articles/Q131/0/65.asp 3817 | static bool enable_privilege(LPCTSTR privilege, bool enable) 3818 | { 3819 | if ( !win32_debmod_t::winver.is_NT() ) // no privileges on 9X/ME 3820 | return true; 3821 | 3822 | bool ok = false; 3823 | if ( init_advapi32() ) 3824 | { 3825 | HANDLE hToken; 3826 | DWORD tokens = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY; 3827 | if ( _OpenProcessToken(GetCurrentProcess(), tokens, &hToken) ) 3828 | { 3829 | LUID luid; 3830 | if ( _LookupPrivilegeValue(NULL, privilege, &luid) ) 3831 | { 3832 | TOKEN_PRIVILEGES tp; 3833 | memset(&tp, 0, sizeof(tp)); 3834 | tp.PrivilegeCount = 1; 3835 | tp.Privileges[0].Luid = luid; 3836 | tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; 3837 | ok = _AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL) != FALSE; 3838 | } 3839 | CloseHandle(hToken); 3840 | } 3841 | term_advapi32(); 3842 | } 3843 | return ok; 3844 | } 3845 | -------------------------------------------------------------------------------- /win32_local_impl.cpp: -------------------------------------------------------------------------------- 1 | #ifndef __NT__ 2 | #define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION 3 | #define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT 4 | #define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT 5 | #define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP 6 | #define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED 7 | #define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND 8 | #define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO 9 | #define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT 10 | #define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION 11 | #define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW 12 | #define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK 13 | #define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW 14 | #define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO 15 | #define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW 16 | #define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION 17 | #define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR 18 | #define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION 19 | #define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION 20 | #define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW 21 | #define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION 22 | #define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION 23 | #define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE 24 | #define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT 25 | #define DBG_CONTROL_C 0x40010005L 26 | #define DBG_CONTROL_BREAK 0x40010008L 27 | #define STATUS_GUARD_PAGE_VIOLATION 0x80000001L 28 | #define STATUS_DATATYPE_MISALIGNMENT 0x80000002L 29 | #define STATUS_BREAKPOINT 0x80000003L 30 | #define STATUS_SINGLE_STEP 0x80000004L 31 | #define STATUS_ACCESS_VIOLATION 0xC0000005L 32 | #define STATUS_IN_PAGE_ERROR 0xC0000006L 33 | #define STATUS_INVALID_HANDLE 0xC0000008L 34 | #define STATUS_NO_MEMORY 0xC0000017L 35 | #define STATUS_ILLEGAL_INSTRUCTION 0xC000001DL 36 | #define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025L 37 | #define STATUS_INVALID_DISPOSITION 0xC0000026L 38 | #define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008CL 39 | #define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008DL 40 | #define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008EL 41 | #define STATUS_FLOAT_INEXACT_RESULT 0xC000008FL 42 | #define STATUS_FLOAT_INVALID_OPERATION 0xC0000090L 43 | #define STATUS_FLOAT_OVERFLOW 0xC0000091L 44 | #define STATUS_FLOAT_STACK_CHECK 0xC0000092L 45 | #define STATUS_FLOAT_UNDERFLOW 0xC0000093L 46 | #define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094L 47 | #define STATUS_INTEGER_OVERFLOW 0xC0000095L 48 | #define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096L 49 | #define STATUS_STACK_OVERFLOW 0xC00000FDL 50 | #define STATUS_CONTROL_C_EXIT 0xC000013AL 51 | #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4L 52 | #define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5L 53 | #define STATUS_REG_NAT_CONSUMPTION 0xC00002C9L 54 | #define SUCCEEDED(x) (x >= 0) 55 | #define FAILED(x) (x < 0) 56 | #endif 57 | 58 | #include 59 | #include 60 | #include "../ldr/pe/pe.h" 61 | #include "../plugins/pdb/pdb.hpp" 62 | #include "win32_rpc.h" 63 | #include "dbg_rpc_hlp.h" 64 | 65 | //-------------------------------------------------------------------------- 66 | static const char idc_win32_rdmsr_args[] = { VT_LONG, 0 }; 67 | static error_t idaapi idc_win32_rdmsr(idc_value_t *argv, idc_value_t *res) 68 | { 69 | uint64 value = 0; // shut up the compiler 70 | uval_t reg = argv[0].num; 71 | #ifdef RPC_CLIENT 72 | void *out = NULL; 73 | ssize_t outsize; 74 | int code = g_dbgmod.send_ioctl(WIN32_IOCTL_RDMSR, ®, sizeof(reg), &out, &outsize); 75 | if ( SUCCEEDED(code) && outsize == sizeof(value) ) 76 | value = *(uint64*)out; 77 | qfree(out); 78 | #else 79 | int code = g_dbgmod.rdmsr(reg, &value); 80 | #endif 81 | if ( FAILED(code) ) 82 | { 83 | res->num = code; 84 | return set_qerrno(eExecThrow); // read error, raise exception 85 | } 86 | res->set_int64(value); 87 | return eOk; 88 | } 89 | 90 | //-------------------------------------------------------------------------- 91 | static const char idc_win32_wrmsr_args[] = { VT_LONG, VT_INT64, 0 }; 92 | static error_t idaapi idc_win32_wrmsr(idc_value_t *argv, idc_value_t *res) 93 | { 94 | win32_wrmsr_t msr; 95 | msr.reg = argv[0].num; 96 | msr.value = argv[1].i64; 97 | #ifdef RPC_CLIENT 98 | res->num = g_dbgmod.send_ioctl(WIN32_IOCTL_WRMSR, &msr, sizeof(msr), NULL, NULL); 99 | #else 100 | res->num = g_dbgmod.wrmsr(msr.reg, msr.value); 101 | #endif 102 | return eOk; 103 | } 104 | 105 | //-------------------------------------------------------------------------- 106 | // Installs or uninstalls debugger specific idc functions 107 | static bool register_idc_funcs(bool reg) 108 | { 109 | static const ext_idcfunc_t idcfuncs[] = 110 | { 111 | { IDC_READ_MSR, idc_win32_rdmsr, idc_win32_rdmsr_args, NULL, 0, 0 }, 112 | { IDC_WRITE_MSR, idc_win32_wrmsr, idc_win32_wrmsr_args, NULL, 0, 0 }, 113 | }; 114 | return add_idc_funcs(idcfuncs, qnumber(idcfuncs), reg); 115 | } 116 | 117 | //-------------------------------------------------------------------------- 118 | void idaapi rebase_if_required_to(ea_t new_base) 119 | { 120 | netnode penode(PE_NODE); 121 | ea_t currentbase = new_base; 122 | ea_t imagebase = ea_t(penode.altval(PE_ALT_IMAGEBASE)); // loading address (usually pe.imagebase) 123 | 124 | if ( imagebase == 0 ) 125 | { 126 | if ( !is_miniidb() ) 127 | warning("AUTOHIDE DATABASE\n" 128 | "IDA could not automatically determine if the program should be\n" 129 | "rebased in the database because the database format is too old and\n" 130 | "doesn't contain enough information.\n" 131 | "Create a new database if you want automated rebasing to work properly.\n" 132 | "Note you can always manually rebase the program by using the\n" 133 | "Edit, Segments, Rebase program command."); 134 | } 135 | else if ( imagebase != currentbase ) 136 | { 137 | rebase_or_warn(imagebase, currentbase); 138 | } 139 | } 140 | 141 | //-------------------------------------------------------------------------- 142 | bool read_pe_header(peheader_t *pe) 143 | { 144 | netnode penode(PE_NODE); 145 | return penode.valobj(pe, sizeof(peheader_t)) > 0; 146 | } 147 | 148 | //-------------------------------------------------------------------------- 149 | // Initialize Win32 debugger plugin 150 | static bool win32_init_plugin(void) 151 | { 152 | // Remote debugger? Then nothing to initialize locally 153 | /* 154 | #ifndef RPC_CLIENT 155 | if ( !init_subsystem() ) 156 | return false; 157 | #endif 158 | if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() ) 159 | { 160 | #ifndef __NT__ 161 | // local debugger is available if we are running under Windows 162 | // for other systems only the remote debugger is available 163 | if ( !debugger.is_remote() ) 164 | return false; 165 | #endif 166 | } 167 | else 168 | { 169 | if ( inf_get_filetype() != f_PE ) 170 | return false; // only PE files 171 | 172 | processor_t &ph = PH; 173 | if ( ph.id != TARGET_PROCESSOR && ph.id != -1 ) 174 | return false; 175 | 176 | // find out the pe header 177 | peheader_t pe; 178 | if ( !read_pe_header(&pe) ) 179 | return false; 180 | 181 | // debug only gui, console, or unknown applications 182 | if ( pe.subsys != PES_WINGUI // Windows GUI 183 | && pe.subsys != PES_WINCHAR // Windows Character 184 | && pe.subsys != PES_UNKNOWN ) // Unknown 185 | { 186 | return false; 187 | } 188 | } 189 | */ 190 | return true; 191 | } 192 | 193 | //-------------------------------------------------------------------------- 194 | inline void win32_term_plugin(void) 195 | { 196 | #ifndef RPC_CLIENT 197 | term_subsystem(); 198 | #endif 199 | } 200 | 201 | //---------------------------------------------------------------------------- 202 | struct pdb_remote_session_t; 203 | void close_pdb_remote_session(pdb_remote_session_t *) 204 | { 205 | } 206 | 207 | #ifndef HAVE_PLUGIN_COMMENTS 208 | //-------------------------------------------------------------------------- 209 | static const char comment[] = "Userland win32 debugger plugin"; 210 | #endif 211 | -------------------------------------------------------------------------------- /win32_user.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is main source code for the local win32 debugger module 3 | */ 4 | 5 | static const char wanted_name[] = "IDA Debug Bridge"; 6 | 7 | #define DEBUGGER_NAME "win32" 8 | #define PROCESSOR_NAME "metapc" 9 | #define TARGET_PROCESSOR PLFM_386 10 | #define DEBUGGER_ID 66 11 | #define DEBUGGER_FLAGS (DBG_FLAG_EXITSHOTOK \ 12 | | DBG_FLAG_LOWCNDS \ 13 | | DBG_FLAG_DEBTHREAD \ 14 | | DBG_FLAG_ANYSIZE_HWBPT) 15 | #define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO) 16 | 17 | #define HAVE_APPCALL 18 | #define S_FILETYPE f_PE 19 | 20 | // We must rename those method because common files 21 | // refer to them as init_plugin/term_plugin 22 | // Some other debugger modules compatible with win32 23 | // have their own init/term and still call win32_init/term 24 | // (since no renaming takes place) 25 | #define win32_init_plugin init_plugin 26 | #define win32_term_plugin term_plugin 27 | 28 | #define WIN32_LEAN_AND_MEAN 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "win32_debmod.h" 37 | #include "w32sehch.h" 38 | 39 | win32_debmod_t g_dbgmod; 40 | #include "common_stub_impl.cpp" 41 | 42 | #include "pc_local_impl.cpp" 43 | #include "win32_local_impl.cpp" 44 | #include "common_local_impl.cpp" 45 | 46 | #include "win32_server_stub.cpp" 47 | --------------------------------------------------------------------------------