├── 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 |
--------------------------------------------------------------------------------