metasm 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,2027 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ require 'metasm/os/main'
7
+ require 'metasm/dynldr'
8
+
9
+ module Metasm
10
+ class WinAPI < DynLdr
11
+ def self.api_not_found(lib, func)
12
+ puts "could not find symbol #{func.name.inspect} in #{lib.inspect}" if $VERBOSE and not func.attributes.to_a.include?('optional')
13
+ end
14
+
15
+ new_api_c <<EOS, 'kernel32'
16
+ #line #{__LINE__}
17
+
18
+ typedef char CHAR;
19
+ typedef unsigned char BYTE;
20
+ typedef unsigned short WORD, USHORT;
21
+ typedef unsigned int UINT;
22
+ typedef long LONG;
23
+ typedef unsigned long ULONG, DWORD, *LPDWORD;
24
+ typedef int BOOL;
25
+ typedef unsigned long long DWORD64, ULONGLONG;
26
+
27
+ typedef intptr_t INT_PTR, LONG_PTR;
28
+ typedef uintptr_t UINT_PTR, ULONG_PTR, DWORD_PTR, SIZE_T;
29
+ typedef LONG_PTR LPARAM;
30
+ typedef UINT_PTR WPARAM;
31
+ typedef LONG_PTR LRESULT;
32
+ typedef const CHAR *LPSTR, *LPCSTR;
33
+ typedef void VOID, *PVOID, *LPVOID;
34
+
35
+ typedef void *HANDLE;
36
+ typedef void *HMODULE;
37
+
38
+ #define INVALID_HANDLE_VALUE (HANDLE)-1
39
+ #define DECLSPEC_IMPORT __declspec(dllimport)
40
+ #define WINUSERAPI DECLSPEC_IMPORT
41
+ #define WINBASEAPI DECLSPEC_IMPORT
42
+ #define WINAPI __stdcall
43
+ #define CALLBACK __stdcall
44
+ #define CONST const
45
+ #define ZEROOK __attribute__((zero_not_fail))
46
+ #define __in __attribute__((in))
47
+ #define __out __attribute__((out))
48
+ #define __opt __attribute__((opt))
49
+ #define __inout __in __out
50
+ #define __in_opt __in __opt
51
+ #define __out_opt __out __opt
52
+ #define __inout_opt __inout __opt
53
+
54
+ #define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
55
+ #define INFINITE 0xFFFFFFFF
56
+
57
+ #define PAGE_NOACCESS 0x01
58
+ #define PAGE_READONLY 0x02
59
+ #define PAGE_READWRITE 0x04
60
+ #define PAGE_WRITECOPY 0x08
61
+ #define PAGE_EXECUTE 0x10
62
+ #define PAGE_EXECUTE_READ 0x20
63
+ #define PAGE_EXECUTE_READWRITE 0x40
64
+ #define PAGE_EXECUTE_WRITECOPY 0x80
65
+ #define PAGE_GUARD 0x100
66
+ #define PAGE_NOCACHE 0x200
67
+ #define PAGE_WRITECOMBINE 0x400
68
+ #define MEM_COMMIT 0x1000
69
+ #define MEM_RESERVE 0x2000
70
+ #define MEM_DECOMMIT 0x4000
71
+ #define MEM_RELEASE 0x8000
72
+ #define MEM_FREE 0x10000
73
+ #define MEM_PRIVATE 0x20000
74
+ #define MEM_MAPPED 0x40000
75
+ #define MEM_RESET 0x80000
76
+ #define MEM_TOP_DOWN 0x100000
77
+ #define MEM_WRITE_WATCH 0x200000
78
+ #define MEM_PHYSICAL 0x400000
79
+ #define MEM_LARGE_PAGES 0x20000000
80
+ #define MEM_4MB_PAGES 0x80000000
81
+ #define SEC_FILE 0x800000
82
+ #define SEC_IMAGE 0x1000000
83
+ #define SEC_RESERVE 0x4000000
84
+ #define SEC_COMMIT 0x8000000
85
+ #define SEC_NOCACHE 0x10000000
86
+ #define SEC_LARGE_PAGES 0x80000000
87
+ #define MEM_IMAGE SEC_IMAGE
88
+
89
+ #define DEBUG_PROCESS 0x00000001
90
+ #define DEBUG_ONLY_THIS_PROCESS 0x00000002
91
+ #define CREATE_SUSPENDED 0x00000004
92
+ #define DETACHED_PROCESS 0x00000008
93
+ #define CREATE_NEW_CONSOLE 0x00000010
94
+ #define NORMAL_PRIORITY_CLASS 0x00000020
95
+ #define IDLE_PRIORITY_CLASS 0x00000040
96
+ #define HIGH_PRIORITY_CLASS 0x00000080
97
+ #define REALTIME_PRIORITY_CLASS 0x00000100
98
+ #define CREATE_NEW_PROCESS_GROUP 0x00000200
99
+ #define CREATE_UNICODE_ENVIRONMENT 0x00000400
100
+ #define CREATE_SEPARATE_WOW_VDM 0x00000800
101
+ #define CREATE_SHARED_WOW_VDM 0x00001000
102
+ #define CREATE_FORCEDOS 0x00002000
103
+ #define BELOW_NORMAL_PRIORITY_CLASS 0x00004000
104
+ #define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
105
+ #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
106
+ #define CREATE_BREAKAWAY_FROM_JOB 0x01000000
107
+ #define CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x02000000
108
+ #define CREATE_DEFAULT_ERROR_MODE 0x04000000
109
+ #define CREATE_NO_WINDOW 0x08000000
110
+ #define PROFILE_USER 0x10000000
111
+ #define PROFILE_KERNEL 0x20000000
112
+ #define PROFILE_SERVER 0x40000000
113
+ #define CREATE_IGNORE_SYSTEM_DEFAULT 0x80000000
114
+
115
+ #define STATUS_WAIT_0 ((DWORD )0x00000000L)
116
+ #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L)
117
+ #define STATUS_USER_APC ((DWORD )0x000000C0L)
118
+ #define STATUS_TIMEOUT ((DWORD )0x00000102L)
119
+ #define STATUS_PENDING ((DWORD )0x00000103L)
120
+ #define DBG_EXCEPTION_HANDLED ((DWORD )0x00010001L)
121
+ #define DBG_CONTINUE ((DWORD )0x00010002L)
122
+ #define STATUS_SEGMENT_NOTIFICATION ((DWORD )0x40000005L)
123
+ #define DBG_TERMINATE_THREAD ((DWORD )0x40010003L)
124
+ #define DBG_TERMINATE_PROCESS ((DWORD )0x40010004L)
125
+ #define DBG_CONTROL_C ((DWORD )0x40010005L)
126
+ #define DBG_CONTROL_BREAK ((DWORD )0x40010008L)
127
+ #define DBG_COMMAND_EXCEPTION ((DWORD )0x40010009L)
128
+ #define STATUS_GUARD_PAGE_VIOLATION ((DWORD )0x80000001L)
129
+ #define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L)
130
+ #define STATUS_BREAKPOINT ((DWORD )0x80000003L)
131
+ #define STATUS_SINGLE_STEP ((DWORD )0x80000004L)
132
+ #define DBG_EXCEPTION_NOT_HANDLED ((DWORD )0x80010001L)
133
+ #define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L)
134
+ #define STATUS_IN_PAGE_ERROR ((DWORD )0xC0000006L)
135
+ #define STATUS_INVALID_HANDLE ((DWORD )0xC0000008L)
136
+ #define STATUS_NO_MEMORY ((DWORD )0xC0000017L)
137
+ #define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL)
138
+ #define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD )0xC0000025L)
139
+ #define STATUS_INVALID_DISPOSITION ((DWORD )0xC0000026L)
140
+ #define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD )0xC000008CL)
141
+ #define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD )0xC000008DL)
142
+ #define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD )0xC000008EL)
143
+ #define STATUS_FLOAT_INEXACT_RESULT ((DWORD )0xC000008FL)
144
+ #define STATUS_FLOAT_INVALID_OPERATION ((DWORD )0xC0000090L)
145
+ #define STATUS_FLOAT_OVERFLOW ((DWORD )0xC0000091L)
146
+ #define STATUS_FLOAT_STACK_CHECK ((DWORD )0xC0000092L)
147
+ #define STATUS_FLOAT_UNDERFLOW ((DWORD )0xC0000093L)
148
+ #define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD )0xC0000094L)
149
+ #define STATUS_INTEGER_OVERFLOW ((DWORD )0xC0000095L)
150
+ #define STATUS_PRIVILEGED_INSTRUCTION ((DWORD )0xC0000096L)
151
+ #define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL)
152
+ #define STATUS_CONTROL_C_EXIT ((DWORD )0xC000013AL)
153
+ #define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD )0xC00002B4L)
154
+ #define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD )0xC00002B5L)
155
+ #define STATUS_REG_NAT_CONSUMPTION ((DWORD )0xC00002C9L)
156
+
157
+ #define EXCEPTION_DEBUG_EVENT 1
158
+ #define CREATE_THREAD_DEBUG_EVENT 2
159
+ #define CREATE_PROCESS_DEBUG_EVENT 3
160
+ #define EXIT_THREAD_DEBUG_EVENT 4
161
+ #define EXIT_PROCESS_DEBUG_EVENT 5
162
+ #define LOAD_DLL_DEBUG_EVENT 6
163
+ #define UNLOAD_DLL_DEBUG_EVENT 7
164
+ #define OUTPUT_DEBUG_STRING_EVENT 8
165
+ #define RIP_EVENT 9
166
+
167
+ #define MAX_PATH 260
168
+
169
+ #define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception
170
+ #define EXCEPTION_MAXIMUM_PARAMETERS 15 // maximum number of exception parameters
171
+
172
+ typedef struct _EXCEPTION_RECORD {
173
+ DWORD ExceptionCode;
174
+ DWORD ExceptionFlags; // noncontinuable
175
+ struct _EXCEPTION_RECORD *ExceptionRecord;
176
+ PVOID ExceptionAddress;
177
+ DWORD NumberParameters;
178
+ ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
179
+ } EXCEPTION_RECORD, *PEXCEPTION_RECORD;
180
+
181
+ typedef struct _EXCEPTION_RECORD32 {
182
+ DWORD ExceptionCode;
183
+ DWORD ExceptionFlags;
184
+ DWORD ExceptionRecord;
185
+ DWORD ExceptionAddress;
186
+ DWORD NumberParameters;
187
+ DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
188
+ } EXCEPTION_RECORD32, *PEXCEPTION_RECORD32;
189
+
190
+ typedef struct _EXCEPTION_RECORD64 {
191
+ DWORD ExceptionCode;
192
+ DWORD ExceptionFlags;
193
+ DWORD64 ExceptionRecord;
194
+ DWORD64 ExceptionAddress;
195
+ DWORD NumberParameters;
196
+ DWORD __unusedAlignment;
197
+ DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
198
+ } EXCEPTION_RECORD64, *PEXCEPTION_RECORD64;
199
+
200
+ typedef struct _EXCEPTION_DEBUG_INFO {
201
+ EXCEPTION_RECORD ExceptionRecord;
202
+ DWORD dwFirstChance;
203
+ } EXCEPTION_DEBUG_INFO, *LPEXCEPTION_DEBUG_INFO;
204
+
205
+ typedef struct _EXCEPTION_DEBUG_INFO32 {
206
+ EXCEPTION_RECORD32 ExceptionRecord;
207
+ DWORD dwFirstChance;
208
+ } EXCEPTION_DEBUG_INFO32;
209
+
210
+ typedef struct _EXCEPTION_DEBUG_INFO64 {
211
+ EXCEPTION_RECORD64 ExceptionRecord;
212
+ DWORD dwFirstChance;
213
+ } EXCEPTION_DEBUG_INFO64;
214
+
215
+ typedef struct _CREATE_THREAD_DEBUG_INFO {
216
+ HANDLE hThread;
217
+ LPVOID lpThreadLocalBase;
218
+ LPVOID lpStartAddress;
219
+ } CREATE_THREAD_DEBUG_INFO, *LPCREATE_THREAD_DEBUG_INFO;
220
+
221
+ typedef struct _CREATE_PROCESS_DEBUG_INFO {
222
+ HANDLE hFile;
223
+ HANDLE hProcess;
224
+ HANDLE hThread;
225
+ LPVOID lpBaseOfImage;
226
+ DWORD dwDebugInfoFileOffset;
227
+ DWORD nDebugInfoSize;
228
+ LPVOID lpThreadLocalBase;
229
+ LPVOID lpStartAddress;
230
+ LPVOID lpImageName;
231
+ WORD fUnicode;
232
+ } CREATE_PROCESS_DEBUG_INFO, *LPCREATE_PROCESS_DEBUG_INFO;
233
+
234
+ typedef struct _EXIT_THREAD_DEBUG_INFO {
235
+ DWORD dwExitCode;
236
+ } EXIT_THREAD_DEBUG_INFO, *LPEXIT_THREAD_DEBUG_INFO;
237
+
238
+ typedef struct _EXIT_PROCESS_DEBUG_INFO {
239
+ DWORD dwExitCode;
240
+ } EXIT_PROCESS_DEBUG_INFO, *LPEXIT_PROCESS_DEBUG_INFO;
241
+
242
+ typedef struct _LOAD_DLL_DEBUG_INFO {
243
+ HANDLE hFile;
244
+ LPVOID lpBaseOfDll;
245
+ DWORD dwDebugInfoFileOffset;
246
+ DWORD nDebugInfoSize;
247
+ LPVOID lpImageName;
248
+ WORD fUnicode;
249
+ } LOAD_DLL_DEBUG_INFO, *LPLOAD_DLL_DEBUG_INFO;
250
+
251
+ typedef struct _UNLOAD_DLL_DEBUG_INFO {
252
+ LPVOID lpBaseOfDll;
253
+ } UNLOAD_DLL_DEBUG_INFO, *LPUNLOAD_DLL_DEBUG_INFO;
254
+
255
+ typedef struct _OUTPUT_DEBUG_STRING_INFO {
256
+ LPSTR lpDebugStringData;
257
+ WORD fUnicode;
258
+ WORD nDebugStringLength;
259
+ } OUTPUT_DEBUG_STRING_INFO, *LPOUTPUT_DEBUG_STRING_INFO;
260
+
261
+ typedef struct _RIP_INFO {
262
+ DWORD dwError;
263
+ DWORD dwType;
264
+ } RIP_INFO, *LPRIP_INFO;
265
+
266
+ typedef struct _DEBUG_EVENT {
267
+ DWORD dwDebugEventCode;
268
+ DWORD dwProcessId;
269
+ DWORD dwThreadId;
270
+ // DWORD pad64; (implicit)
271
+ union {
272
+ EXCEPTION_DEBUG_INFO Exception;
273
+ EXCEPTION_DEBUG_INFO32 Exception32;
274
+ CREATE_THREAD_DEBUG_INFO CreateThread;
275
+ CREATE_PROCESS_DEBUG_INFO CreateProcess;
276
+ EXIT_THREAD_DEBUG_INFO ExitThread;
277
+ EXIT_PROCESS_DEBUG_INFO ExitProcess;
278
+ LOAD_DLL_DEBUG_INFO LoadDll;
279
+ UNLOAD_DLL_DEBUG_INFO UnloadDll;
280
+ OUTPUT_DEBUG_STRING_INFO DebugString;
281
+ RIP_INFO RipInfo;
282
+ } u;
283
+ } DEBUG_EVENT, *LPDEBUG_EVENT;
284
+
285
+ // XXX conflict with structure name..
286
+ #define CONTEXT_I386 0x00010000
287
+ #define CONTEXT_AMD64 0x00100000
288
+
289
+ #define CONTEXT_CONTROL 0x00000001L // SS:SP, CS:IP, FLAGS, BP
290
+ #define CONTEXT_INTEGER 0x00000002L // AX, BX, CX, DX, SI, DI
291
+ #define CONTEXT_SEGMENTS 0x00000004L // DS, ES, FS, GS
292
+ #define CONTEXT_FLOATING_POINT 0x00000008L // 387 state
293
+ #define CONTEXT_DEBUG_REGISTERS 0x00000010L // DB 0-3,6,7
294
+ #define CONTEXT_EXTENDED_REGISTERS 0x00000020L // cpu specific extensions
295
+ #define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS)
296
+ #define CONTEXT_ALL (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS)
297
+
298
+ #define CONTEXT_I386_FULL CONTEXT_I386 | CONTEXT_FULL
299
+ #define CONTEXT_I386_ALL CONTEXT_I386 | CONTEXT_ALL
300
+ #define CONTEXT_AMD64_FULL CONTEXT_AMD64 | CONTEXT_FULL
301
+ #define CONTEXT_AMD64_ALL CONTEXT_AMD64 | CONTEXT_ALL
302
+
303
+ #define MAXIMUM_SUPPORTED_EXTENSION 512
304
+ #define SIZE_OF_80387_REGISTERS 80
305
+
306
+ typedef struct _FPREG { BYTE b[10]; } FPREG;
307
+ typedef struct _XMMREG { ULONGLONG lo, hi; } XMMREG;
308
+
309
+ typedef struct _FLOATING_SAVE_AREA {
310
+ WORD ControlWord;
311
+ WORD res0;
312
+ WORD StatusWord;
313
+ WORD res1;
314
+ WORD TagWord;
315
+ WORD res2;
316
+ DWORD ErrorOffset;
317
+ WORD ErrorSelector;
318
+ WORD ErrorOpcode;
319
+ DWORD DataOffset;
320
+ WORD DataSelector;
321
+ WORD res3;
322
+ FPREG St[8];
323
+ DWORD Cr0NpxState;
324
+ } FLOATING_SAVE_AREA, *PFLOATING_SAVE_AREA;
325
+
326
+ typedef struct _CONTEXT_I386 {
327
+ DWORD ContextFlags;
328
+ DWORD Dr0;
329
+ DWORD Dr1;
330
+ DWORD Dr2;
331
+ DWORD Dr3;
332
+ DWORD Dr6;
333
+ DWORD Dr7;
334
+ FLOATING_SAVE_AREA FloatSave;
335
+ DWORD SegGs;
336
+ DWORD SegFs;
337
+ DWORD SegEs;
338
+ DWORD SegDs;
339
+ DWORD Edi;
340
+ DWORD Esi;
341
+ DWORD Ebx;
342
+ DWORD Edx;
343
+ DWORD Ecx;
344
+ DWORD Eax;
345
+ DWORD Ebp;
346
+ DWORD Eip;
347
+ DWORD SegCs;
348
+ DWORD EFlags;
349
+ DWORD Esp;
350
+ DWORD SegSs;
351
+
352
+ XMMREG Xmm[8];
353
+
354
+ BYTE ExtendedRegisters[24*16];
355
+ } *LPCONTEXT_I386, *LPCONTEXT;
356
+
357
+ typedef struct _CONTEXT_AMD64 {
358
+ DWORD64 P1Home; // Register parameter home addresses.
359
+ DWORD64 P2Home;
360
+ DWORD64 P3Home;
361
+ DWORD64 P4Home;
362
+ DWORD64 P5Home;
363
+ DWORD64 P6Home;
364
+
365
+ DWORD ContextFlags;
366
+ DWORD MxCsr;
367
+
368
+ WORD SegCs;
369
+ WORD SegDs;
370
+ WORD SegEs;
371
+ WORD SegFs;
372
+ WORD SegGs;
373
+ WORD SegSs;
374
+ DWORD RFlags;
375
+
376
+ DWORD64 Dr0;
377
+ DWORD64 Dr1;
378
+ DWORD64 Dr2;
379
+ DWORD64 Dr3;
380
+ DWORD64 Dr6;
381
+ DWORD64 Dr7;
382
+
383
+ DWORD64 Rax;
384
+ DWORD64 Rcx;
385
+ DWORD64 Rdx;
386
+ DWORD64 Rbx;
387
+ DWORD64 Rsp;
388
+ DWORD64 Rbp;
389
+ DWORD64 Rsi;
390
+ DWORD64 Rdi;
391
+ DWORD64 R8;
392
+ DWORD64 R9;
393
+ DWORD64 R10;
394
+ DWORD64 R11;
395
+ DWORD64 R12;
396
+ DWORD64 R13;
397
+ DWORD64 R14;
398
+ DWORD64 R15;
399
+ DWORD64 Rip;
400
+
401
+ WORD ControlWord;
402
+ WORD StatusWord;
403
+ BYTE TagWord;
404
+ BYTE resv1;
405
+ WORD ErrorOpcode;
406
+ DWORD ErrorOffset;
407
+ WORD ErrorSelector;
408
+ WORD resv2;
409
+ DWORD DataAtOffset;
410
+ WORD DataSelector;
411
+ WORD resv3;
412
+ DWORD MxCsr_f;
413
+ DWORD MxCsrMask;
414
+ XMMREG ST[8];
415
+ XMMREG Xmm[16];
416
+
417
+ XMMREG Vector[26];
418
+ DWORD64 VectorControl;
419
+
420
+ DWORD64 DebugControl;
421
+ DWORD64 LastBranchToRip;
422
+ DWORD64 LastBranchFromRip;
423
+ DWORD64 LastExceptionToRip;
424
+ DWORD64 LastExceptionFromRip;
425
+ } *LPCONTEXT_AMD64;
426
+
427
+ typedef struct _EXCEPTION_POINTERS {
428
+ PEXCEPTION_RECORD ExceptionRecord;
429
+ LPCONTEXT ContextRecord;
430
+ } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
431
+
432
+ #define STANDARD_RIGHTS_REQUIRED (0x000F0000L)
433
+ #define SYNCHRONIZE (0x00100000L)
434
+
435
+ #define PROCESS_TERMINATE (0x0001)
436
+ #define PROCESS_CREATE_THREAD (0x0002)
437
+ #define PROCESS_SET_SESSIONID (0x0004)
438
+ #define PROCESS_VM_OPERATION (0x0008)
439
+ #define PROCESS_VM_READ (0x0010)
440
+ #define PROCESS_VM_WRITE (0x0020)
441
+ #define PROCESS_DUP_HANDLE (0x0040)
442
+ #define PROCESS_CREATE_PROCESS (0x0080)
443
+ #define PROCESS_SET_QUOTA (0x0100)
444
+ #define PROCESS_SET_INFORMATION (0x0200)
445
+ #define PROCESS_QUERY_INFORMATION (0x0400)
446
+ #define PROCESS_SUSPEND_RESUME (0x0800)
447
+ #define PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
448
+ #define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
449
+
450
+ #define THREAD_TERMINATE (0x0001)
451
+ #define THREAD_SUSPEND_RESUME (0x0002)
452
+ #define THREAD_GET_CONTEXT (0x0008)
453
+ #define THREAD_SET_CONTEXT (0x0010)
454
+ #define THREAD_SET_INFORMATION (0x0020)
455
+ #define THREAD_QUERY_INFORMATION (0x0040)
456
+ #define THREAD_SET_THREAD_TOKEN (0x0080)
457
+ #define THREAD_IMPERSONATE (0x0100)
458
+ #define THREAD_DIRECT_IMPERSONATION (0x0200)
459
+ #define THREAD_SET_LIMITED_INFORMATION (0x0400)
460
+ #define THREAD_QUERY_LIMITED_INFORMATION (0x0800)
461
+ #define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF)
462
+
463
+
464
+ typedef struct _STARTUPINFOA {
465
+ DWORD cb;
466
+ LPSTR lpReserved;
467
+ LPSTR lpDesktop;
468
+ LPSTR lpTitle;
469
+ DWORD dwX;
470
+ DWORD dwY;
471
+ DWORD dwXSize;
472
+ DWORD dwYSize;
473
+ DWORD dwXCountChars;
474
+ DWORD dwYCountChars;
475
+ DWORD dwFillAttribute;
476
+ DWORD dwFlags;
477
+ WORD wShowWindow;
478
+ WORD cbReserved2;
479
+ LPVOID lpReserved2;
480
+ HANDLE hStdInput;
481
+ HANDLE hStdOutput;
482
+ HANDLE hStdError;
483
+ } STARTUPINFOA, *LPSTARTUPINFOA;
484
+
485
+ typedef struct _PROCESS_INFORMATION {
486
+ HANDLE hProcess;
487
+ HANDLE hThread;
488
+ DWORD dwProcessId;
489
+ DWORD dwThreadId;
490
+ } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
491
+
492
+
493
+ WINBASEAPI
494
+ HANDLE
495
+ WINAPI
496
+ OpenProcess(
497
+ __in DWORD dwDesiredAccess,
498
+ __in BOOL bInheritHandle,
499
+ __in DWORD dwProcessId
500
+ );
501
+
502
+ WINBASEAPI
503
+ HANDLE
504
+ WINAPI
505
+ GetCurrentProcess(VOID);
506
+
507
+ WINBASEAPI
508
+ DWORD
509
+ WINAPI
510
+ GetCurrentProcessId(VOID);
511
+
512
+ WINBASEAPI
513
+ BOOL
514
+ WINAPI
515
+ TerminateProcess(
516
+ __in HANDLE hProcess,
517
+ __in UINT uExitCode);
518
+
519
+ WINBASEAPI
520
+ BOOL
521
+ WINAPI
522
+ GetExitCodeProcess(
523
+ __in HANDLE hProcess,
524
+ __out LPDWORD lpExitCode);
525
+
526
+ WINBASEAPI
527
+ HANDLE
528
+ WINAPI
529
+ CreateRemoteThread(
530
+ __in HANDLE hProcess,
531
+ __in_opt LPVOID lpThreadAttributes,
532
+ __in DWORD dwStackSize,
533
+ __in LPVOID lpStartAddress,
534
+ __in_opt LPVOID lpParameter,
535
+ __in DWORD dwCreationFlags,
536
+ __out_opt LPDWORD lpThreadId);
537
+
538
+ /* Vista onwards only..
539
+ WINBASEAPI
540
+ DWORD
541
+ WINAPI
542
+ GetThreadId(
543
+ __in HANDLE Thread);
544
+ */
545
+
546
+ WINBASEAPI
547
+ DWORD
548
+ WINAPI
549
+ GetProcessId(
550
+ __in HANDLE Process);
551
+
552
+ WINBASEAPI
553
+ HANDLE
554
+ WINAPI
555
+ OpenThread(
556
+ __in DWORD dwDesiredAccess,
557
+ __in BOOL bInheritHandle,
558
+ __in DWORD dwThreadId);
559
+
560
+ WINBASEAPI
561
+ BOOL
562
+ WINAPI
563
+ TerminateThread(
564
+ __in HANDLE hThread,
565
+ __in DWORD dwExitCode);
566
+
567
+ WINBASEAPI
568
+ BOOL
569
+ WINAPI
570
+ GetExitCodeThread(
571
+ __in HANDLE hThread,
572
+ __out LPDWORD lpExitCode);
573
+
574
+ ZEROOK
575
+ WINBASEAPI
576
+ DWORD
577
+ WINAPI
578
+ GetLastError(VOID);
579
+
580
+ ZEROOK
581
+ WINBASEAPI
582
+ BOOL
583
+ WINAPI
584
+ ReadProcessMemory(
585
+ __in HANDLE hProcess,
586
+ __in LPVOID lpBaseAddress,
587
+ __out LPVOID lpBuffer,
588
+ __in DWORD nSize,
589
+ __out_opt DWORD *lpNumberOfBytesRead);
590
+
591
+ WINBASEAPI
592
+ BOOL
593
+ WINAPI
594
+ WriteProcessMemory(
595
+ __in HANDLE hProcess,
596
+ __in LPVOID lpBaseAddress,
597
+ __in LPVOID lpBuffer,
598
+ __in DWORD nSize,
599
+ __out_opt DWORD *lpNumberOfBytesWritten);
600
+
601
+ WINBASEAPI
602
+ BOOL
603
+ WINAPI
604
+ GetThreadContext(
605
+ __in HANDLE hThread,
606
+ __inout LPCONTEXT lpContext);
607
+
608
+ WINBASEAPI
609
+ BOOL
610
+ WINAPI
611
+ SetThreadContext(
612
+ __in HANDLE hThread,
613
+ __in LPCONTEXT lpContext);
614
+
615
+ WINBASEAPI
616
+ BOOL
617
+ WINAPI
618
+ __attribute__((optional))
619
+ Wow64GetThreadContext(
620
+ __in HANDLE hThread,
621
+ __inout LPCONTEXT_I386 lpContext);
622
+
623
+ WINBASEAPI
624
+ BOOL
625
+ WINAPI
626
+ __attribute__((optional))
627
+ Wow64SetThreadContext(
628
+ __in HANDLE hThread,
629
+ __inout LPCONTEXT_I386 lpContext);
630
+
631
+ ZEROOK
632
+ WINBASEAPI
633
+ DWORD
634
+ WINAPI
635
+ SuspendThread(
636
+ __in HANDLE hThread);
637
+
638
+ ZEROOK
639
+ WINBASEAPI
640
+ DWORD
641
+ WINAPI
642
+ __attribute__((optional))
643
+ Wow64SuspendThread(
644
+ __in HANDLE hThread);
645
+
646
+ ZEROOK
647
+ WINBASEAPI
648
+ DWORD
649
+ WINAPI
650
+ ResumeThread(
651
+ __in HANDLE hThread);
652
+
653
+ WINBASEAPI
654
+ VOID
655
+ WINAPI
656
+ DebugBreak(VOID);
657
+
658
+ ZEROOK
659
+ WINBASEAPI
660
+ BOOL
661
+ WINAPI
662
+ WaitForDebugEvent(
663
+ __in LPDEBUG_EVENT lpDebugEvent,
664
+ __in DWORD dwMilliseconds);
665
+
666
+ WINBASEAPI
667
+ BOOL
668
+ WINAPI
669
+ ContinueDebugEvent(
670
+ __in DWORD dwProcessId,
671
+ __in DWORD dwThreadId,
672
+ __in DWORD dwContinueStatus);
673
+
674
+ WINBASEAPI
675
+ BOOL
676
+ WINAPI
677
+ DebugActiveProcess(
678
+ __in DWORD dwProcessId);
679
+
680
+ WINBASEAPI
681
+ BOOL
682
+ WINAPI
683
+ DebugActiveProcessStop(
684
+ __in DWORD dwProcessId);
685
+
686
+ WINBASEAPI
687
+ BOOL
688
+ WINAPI
689
+ DebugSetProcessKillOnExit(
690
+ __in BOOL KillOnExit);
691
+
692
+ WINBASEAPI
693
+ BOOL
694
+ WINAPI
695
+ DebugBreakProcess (
696
+ __in HANDLE Process);
697
+
698
+ ZEROOK
699
+ WINBASEAPI
700
+ DWORD
701
+ WINAPI
702
+ FormatMessageA(
703
+ DWORD dwFlags,
704
+ LPVOID lpSource,
705
+ DWORD dwMessageId,
706
+ DWORD dwLanguageId,
707
+ LPSTR lpBuffer,
708
+ DWORD nSize,
709
+ LPVOID Arguments);
710
+
711
+ WINBASEAPI
712
+ BOOL
713
+ WINAPI
714
+ CreateProcessA(
715
+ __in_opt LPCSTR lpApplicationName,
716
+ __inout_opt LPSTR lpCommandLine,
717
+ __in_opt LPVOID lpProcessAttributes,
718
+ __in_opt LPVOID lpThreadAttributes,
719
+ __in BOOL bInheritHandles,
720
+ __in DWORD dwCreationFlags,
721
+ __in_opt LPVOID lpEnvironment,
722
+ __in_opt LPCSTR lpCurrentDirectory,
723
+ __in LPSTARTUPINFOA lpStartupInfo,
724
+ __out LPPROCESS_INFORMATION lpProcessInformation);
725
+
726
+ WINBASEAPI
727
+ BOOL
728
+ WINAPI
729
+ CloseHandle(
730
+ __in HANDLE hObject);
731
+
732
+ WINBASEAPI
733
+ LPVOID
734
+ WINAPI
735
+ VirtualAllocEx(
736
+ __in HANDLE hProcess,
737
+ __in_opt LPVOID lpAddress,
738
+ __in SIZE_T dwSize,
739
+ __in DWORD flAllocationType,
740
+ __in DWORD flProtect);
741
+
742
+ WINBASEAPI
743
+ BOOL
744
+ WINAPI
745
+ VirtualFreeEx(
746
+ __in HANDLE hProcess,
747
+ __in LPVOID lpAddress,
748
+ __in SIZE_T dwSize,
749
+ __in DWORD dwFreeType);
750
+
751
+ WINBASEAPI
752
+ BOOL
753
+ WINAPI
754
+ VirtualProtectEx(
755
+ __in HANDLE hProcess,
756
+ __in LPVOID lpAddress,
757
+ __in SIZE_T dwSize,
758
+ __in DWORD flNewProtect,
759
+ __out LPDWORD lpflOldProtect);
760
+
761
+ #define TH32CS_SNAPHEAPLIST 0x00000001
762
+ #define TH32CS_SNAPPROCESS 0x00000002
763
+ #define TH32CS_SNAPTHREAD 0x00000004
764
+ #define TH32CS_SNAPMODULE 0x00000008
765
+ #define TH32CS_SNAPMODULE32 0x00000010
766
+ #define TH32CS_INHERIT 0x80000000
767
+
768
+ HANDLE
769
+ WINAPI
770
+ CreateToolhelp32Snapshot(
771
+ DWORD dwFlags,
772
+ DWORD th32ProcessID
773
+ );
774
+
775
+ typedef struct tagPROCESSENTRY32
776
+ {
777
+ DWORD dwSize;
778
+ DWORD cntUsage;
779
+ DWORD th32ProcessID;
780
+ ULONG_PTR th32DefaultHeapID;
781
+ DWORD th32ModuleID;
782
+ DWORD cntThreads;
783
+ DWORD th32ParentProcessID;
784
+ LONG pcPriClassBase;
785
+ DWORD dwFlags;
786
+ CHAR szExeFile[MAX_PATH];
787
+ } PROCESSENTRY32;
788
+
789
+ BOOL
790
+ WINAPI
791
+ Process32First(
792
+ HANDLE hSnapshot,
793
+ PROCESSENTRY32 *lppe
794
+ );
795
+ BOOL
796
+ WINAPI
797
+ ZEROOK
798
+ Process32Next(
799
+ HANDLE hSnapshot,
800
+ PROCESSENTRY32 *lppe
801
+ );
802
+
803
+
804
+ typedef struct tagTHREADENTRY32
805
+ {
806
+ DWORD dwSize;
807
+ DWORD cntUsage;
808
+ DWORD th32ThreadID; // this thread
809
+ DWORD th32OwnerProcessID; // Process this thread is associated with
810
+ LONG tpBasePri;
811
+ LONG tpDeltaPri;
812
+ DWORD dwFlags;
813
+ } THREADENTRY32, * LPTHREADENTRY32;
814
+
815
+ BOOL
816
+ WINAPI
817
+ Thread32First(
818
+ HANDLE hSnapshot,
819
+ LPTHREADENTRY32 lpte
820
+ );
821
+ BOOL
822
+ WINAPI
823
+ ZEROOK
824
+ Thread32Next(
825
+ HANDLE hSnapshot,
826
+ LPTHREADENTRY32 lpte
827
+ );
828
+
829
+
830
+ typedef struct tagHEAPLIST32
831
+ {
832
+ SIZE_T dwSize;
833
+ DWORD th32ProcessID; // owning process
834
+ ULONG_PTR th32HeapID; // heap (in owning process context!)
835
+ DWORD dwFlags;
836
+ } HEAPLIST32, LPHEAPLIST32;
837
+
838
+ #define HF32_DEFAULT 1 // process default heap
839
+ #define HF32_SHARED 2 // is shared heap
840
+
841
+ BOOL
842
+ WINAPI
843
+ Heap32ListFirst(
844
+ HANDLE hSnapshot,
845
+ LPHEAPLIST32 lphl
846
+ );
847
+ BOOL
848
+ WINAPI
849
+ ZEROOK
850
+ Heap32ListNext(
851
+ HANDLE hSnapshot,
852
+ LPHEAPLIST32 lphl
853
+ );
854
+
855
+
856
+ typedef struct tagMODULEENTRY32
857
+ {
858
+ DWORD dwSize;
859
+ DWORD th32ModuleID;
860
+ DWORD th32ProcessID;
861
+ DWORD GlblcntUsage;
862
+ DWORD ProccntUsage;
863
+ ULONG_PTR modBaseAddr;
864
+ DWORD modBaseSize;
865
+ HMODULE hModule;
866
+ char szModule[256];
867
+ char szExePath[MAX_PATH];
868
+ } MODULEENTRY32;
869
+
870
+ BOOL
871
+ WINAPI
872
+ Module32First(
873
+ HANDLE hSnapshot,
874
+ MODULEENTRY32 *lpme
875
+ );
876
+ BOOL
877
+ WINAPI
878
+ ZEROOK
879
+ Module32Next(
880
+ HANDLE hSnapshot,
881
+ MODULEENTRY32 *lpme
882
+ );
883
+
884
+
885
+ typedef struct _MEMORY_BASIC_INFORMATION32 {
886
+ DWORD BaseAddress;
887
+ DWORD AllocationBase;
888
+ DWORD AllocationProtect; // initial (alloc time) prot
889
+ DWORD RegionSize;
890
+ DWORD State; // MEM_FREE/COMMIT/RESERVE
891
+ DWORD Protect; // PAGE_EXECUTE_READWRITE etc
892
+ DWORD Type; // MEM_IMAGE/MAPPED/PRIVATE
893
+ } MEMORY_BASIC_INFORMATION32, *PMEMORY_BASIC_INFORMATION32;
894
+
895
+ typedef struct _MEMORY_BASIC_INFORMATION64 {
896
+ ULONGLONG BaseAddress;
897
+ ULONGLONG AllocationBase;
898
+ DWORD AllocationProtect;
899
+ DWORD __alignment1;
900
+ ULONGLONG RegionSize;
901
+ DWORD State;
902
+ DWORD Protect;
903
+ DWORD Type;
904
+ DWORD __alignment2;
905
+ } MEMORY_BASIC_INFORMATION64, *PMEMORY_BASIC_INFORMATION64;
906
+
907
+ SIZE_T
908
+ WINAPI
909
+ ZEROOK
910
+ VirtualQueryEx(
911
+ HANDLE hProcess,
912
+ LPVOID lpAddress,
913
+ PMEMORY_BASIC_INFORMATION32 lpBuffer,
914
+ SIZE_T dwLength // sizeof lpBuffer
915
+ );
916
+
917
+ typedef struct _LDT_ENTRY {
918
+ WORD LimitLow;
919
+ WORD BaseLow;
920
+ union {
921
+ struct {
922
+ BYTE BaseMid;
923
+ BYTE Flags1;
924
+ BYTE Flags2;
925
+ BYTE BaseHi;
926
+ } Bytes;
927
+ struct {
928
+ DWORD BaseMid :8;
929
+ DWORD Type :5;
930
+ DWORD Dpl :2;
931
+ DWORD Pres :1;
932
+ DWORD LimitHi :4;
933
+ DWORD Sys :1;
934
+ DWORD Reserved_0 :1;
935
+ DWORD Default_Big :1;
936
+ DWORD Granularity :1;
937
+ DWORD BaseHi :8;
938
+ } Bits;
939
+ } HighWord;
940
+ } LDT_ENTRY;
941
+
942
+ BOOL
943
+ WINAPI
944
+ GetThreadSelectorEntry(
945
+ HANDLE hThread,
946
+ DWORD dwSelector,
947
+ LDT_ENTRY *lpSelectorEntry
948
+ );
949
+
950
+ BOOL
951
+ WINAPI
952
+ __attribute__((optional))
953
+ IsWow64Process(
954
+ HANDLE hProcess,
955
+ BOOL *wow64
956
+ );
957
+
958
+ EOS
959
+
960
+ new_api_c <<EOS, 'advapi32'
961
+ #line #{__LINE__}
962
+
963
+ #define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L)
964
+ #define SE_PRIVILEGE_ENABLED (0x00000002L)
965
+ #define SE_PRIVILEGE_REMOVED (0X00000004L)
966
+ #define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L)
967
+
968
+ #define TOKEN_ASSIGN_PRIMARY (0x0001)
969
+ #define TOKEN_DUPLICATE (0x0002)
970
+ #define TOKEN_IMPERSONATE (0x0004)
971
+ #define TOKEN_QUERY (0x0008)
972
+ #define TOKEN_QUERY_SOURCE (0x0010)
973
+ #define TOKEN_ADJUST_PRIVILEGES (0x0020)
974
+ #define TOKEN_ADJUST_GROUPS (0x0040)
975
+ #define TOKEN_ADJUST_DEFAULT (0x0080)
976
+ #define TOKEN_ADJUST_SESSIONID (0x0100)
977
+
978
+ typedef struct _LUID {
979
+ DWORD LowPart;
980
+ LONG HighPart;
981
+ } LUID, *PLUID;
982
+
983
+ typedef struct _LUID_AND_ATTRIBUTES {
984
+ LUID Luid;
985
+ DWORD Attributes;
986
+ } LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;
987
+
988
+ typedef struct _TOKEN_PRIVILEGES {
989
+ DWORD PrivilegeCount;
990
+ LUID_AND_ATTRIBUTES Privileges[1];
991
+ } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
992
+
993
+
994
+ BOOL
995
+ WINAPI
996
+ LookupPrivilegeNameA(
997
+ __in_opt LPCSTR lpSystemName,
998
+ __in PLUID lpLuid,
999
+ __out LPSTR lpName,
1000
+ __inout LPDWORD cchName);
1001
+
1002
+ BOOL
1003
+ WINAPI
1004
+ LookupPrivilegeValueA(
1005
+ __in_opt LPCSTR lpSystemName,
1006
+ __in LPCSTR lpName,
1007
+ __out PLUID lpLuid);
1008
+
1009
+ BOOL
1010
+ WINAPI
1011
+ AdjustTokenPrivileges (
1012
+ __in HANDLE TokenHandle,
1013
+ __in BOOL DisableAllPrivileges,
1014
+ __in_opt PTOKEN_PRIVILEGES NewState,
1015
+ __in DWORD BufferLength,
1016
+ __out PTOKEN_PRIVILEGES PreviousState,
1017
+ __out_opt DWORD *ReturnLength);
1018
+
1019
+ BOOL
1020
+ WINAPI
1021
+ OpenProcessToken (
1022
+ __in HANDLE ProcessHandle,
1023
+ __in DWORD DesiredAccess,
1024
+ __out HANDLE *TokenHandle);
1025
+
1026
+
1027
+ BOOL
1028
+ WINAPI
1029
+ OpenThreadToken (
1030
+ __in HANDLE ThreadHandle,
1031
+ __in DWORD DesiredAccess,
1032
+ __in BOOL OpenAsSelf,
1033
+ __out HANDLE *TokenHandle);
1034
+ EOS
1035
+ SE_DEBUG_NAME = 'SeDebugPrivilege'
1036
+
1037
+ new_api_c <<EOS, 'ntdll'
1038
+ #line #{__LINE__}
1039
+
1040
+ typedef LONG NTSTATUS;
1041
+
1042
+ typedef enum _PROCESSINFOCLASS {
1043
+ ProcessBasicInformation,
1044
+ ProcessQuotaLimits,
1045
+ ProcessIoCounters,
1046
+ ProcessVmCounters,
1047
+ ProcessTimes,
1048
+ ProcessBasePriority,
1049
+ ProcessRaisePriority,
1050
+ ProcessDebugPort,
1051
+ ProcessExceptionPort,
1052
+ ProcessAccessToken,
1053
+ ProcessLdtInformation,
1054
+ ProcessLdtSize,
1055
+ ProcessDefaultHardErrorMode,
1056
+ ProcessIoPortHandlers,
1057
+ ProcessPooledUsageAndLimits,
1058
+ ProcessWorkingSetWatch,
1059
+ ProcessUserModeIOPL,
1060
+ ProcessEnableAlignmentFaultFixup,
1061
+ ProcessPriorityClass,
1062
+ ProcessWx86Information,
1063
+ ProcessHandleCount,
1064
+ ProcessAffinityMask,
1065
+ ProcessPriorityBoost,
1066
+ ProcessDeviceMap,
1067
+ ProcessSessionInformation,
1068
+ ProcessForegroundInformation,
1069
+ ProcessWow64Information,
1070
+ ProcessImageFileName,
1071
+ ProcessLUIDDeviceMapsEnabled,
1072
+ ProcessBreakOnTermination,
1073
+ ProcessDebugObjectHandle,
1074
+ ProcessDebugFlags,
1075
+ ProcessHandleTracing
1076
+ } PROCESSINFOCLASS;
1077
+
1078
+ typedef enum _THREADINFOCLASS {
1079
+ ThreadBasicInformation,
1080
+ ThreadTimes,
1081
+ ThreadPriority,
1082
+ ThreadBasePriority,
1083
+ ThreadAffinityMask,
1084
+ ThreadImpersonationToken,
1085
+ ThreadDescriptorTableEntry,
1086
+ ThreadEnableAlignmentFaultFixup,
1087
+ ThreadEventPair_Reusable,
1088
+ ThreadQuerySetWin32StartAddress,
1089
+ ThreadZeroTlsCell,
1090
+ ThreadPerformanceCount,
1091
+ ThreadAmILastThread,
1092
+ ThreadIdealProcessor,
1093
+ ThreadPriorityBoost,
1094
+ ThreadSetTlsArrayAddress,
1095
+ ThreadIsIoPending,
1096
+ ThreadHideFromDebugger,
1097
+ ThreadBreakOnTermination
1098
+ } THREADINFOCLASS;
1099
+
1100
+ typedef enum _MEMORYINFOCLASS {
1101
+ MemoryBasicInformation,
1102
+ MemoryDunnoLol,
1103
+ MemoryMapFileName
1104
+ } MEMORYINFOCLASS;
1105
+
1106
+ typedef struct _CLIENT_ID {
1107
+ HANDLE UniqueProcess;
1108
+ HANDLE UniqueThread;
1109
+ } CLIENT_ID;
1110
+
1111
+ typedef struct _PROCESS_BASIC_INFORMATION {
1112
+ PVOID Reserved1;
1113
+ PVOID PebBaseAddress;
1114
+ PVOID Reserved2[2];
1115
+ ULONG_PTR UniqueProcessId;
1116
+ PVOID Reserved3;
1117
+ } PROCESS_BASIC_INFORMATION;
1118
+
1119
+ typedef struct _THREAD_BASIC_INFORMATION {
1120
+ NTSTATUS ExitStatus;
1121
+ PVOID TebBaseAddress;
1122
+ CLIENT_ID ClientId;
1123
+ ULONG_PTR AffinityMask;
1124
+ LONG Priority;
1125
+ LONG BasePriority;
1126
+ } THREAD_BASIC_INFORMATION;
1127
+
1128
+ typedef struct _UNICODE_STRING {
1129
+ USHORT Length;
1130
+ USHORT MaximumLength;
1131
+ USHORT *Buffer;
1132
+ } UNICODE_STRING;
1133
+
1134
+ ZEROOK
1135
+ NTSTATUS
1136
+ WINAPI
1137
+ NtQueryInformationProcess(
1138
+ HANDLE ProcessHandle,
1139
+ PROCESSINFOCLASS ProcessInformationClass,
1140
+ PVOID ProcessInformation,
1141
+ ULONG ProcessInformationLength,
1142
+ ULONG *ReturnLength
1143
+ );
1144
+
1145
+ ZEROOK
1146
+ NTSTATUS
1147
+ WINAPI
1148
+ NtQueryInformationThread (
1149
+ HANDLE ThreadHandle,
1150
+ THREADINFOCLASS ThreadInformationClass,
1151
+ PVOID ThreadInformation,
1152
+ ULONG ThreadInformationLength,
1153
+ ULONG *ReturnLength
1154
+ );
1155
+
1156
+ ZEROOK
1157
+ NTSTATUS
1158
+ WINAPI
1159
+ NtQueryVirtualMemory (
1160
+ HANDLE ProcessHandle,
1161
+ PVOID BaseAddress,
1162
+ MEMORYINFOCLASS MemoryInformationClass,
1163
+ PVOID MemoryInformation,
1164
+ ULONG MemoryInformationLength,
1165
+ ULONG *ReturnLength
1166
+ );
1167
+
1168
+ EOS
1169
+
1170
+ # convert a native function return value
1171
+ # if the native does not have the zero_not_fail attribute, convert 0
1172
+ # to nil, and print a message on stdout
1173
+ def self.convert_ret_c2rb(fproto, ret)
1174
+ @last_err_msg = nil
1175
+ if ret == 0 and not fproto.has_attribute 'zero_not_fail'
1176
+ # save error msg so that last_error_msg returns the same thing if called again
1177
+ puts "WinAPI: error in #{fproto.name}: #{@last_err_msg = last_error_msg}" if $VERBOSE
1178
+ nil
1179
+ else super(fproto, ret)
1180
+ end
1181
+ end
1182
+
1183
+ # retrieve the textual error message relative to GetLastError
1184
+ def self.last_error_msg(errno = nil)
1185
+ return @last_err_msg if @last_err_msg
1186
+ errno ||= getlasterror
1187
+ message = ' '*512
1188
+ if formatmessagea(FORMAT_MESSAGE_FROM_SYSTEM, nil, errno, 0, message, message.length, nil) == 0
1189
+ message = 'unknown error %x' % errno
1190
+ else
1191
+ message = message[0, message.index(?\0)] if message.index(?\0)
1192
+ message.chomp!
1193
+ end
1194
+ message
1195
+ end
1196
+ end
1197
+
1198
+ class WinOS < OS
1199
+ class Process < OS::Process
1200
+ attr_accessor :ppid
1201
+ def initialize(pid, handle=nil)
1202
+ @pid = pid
1203
+ @handle = handle
1204
+ end
1205
+
1206
+ # on-demand cached openprocess(ALL_ACCESS) handle
1207
+ def handle
1208
+ @handle ||= WinAPI.openprocess(WinAPI::PROCESS_ALL_ACCESS, 0, @pid)
1209
+ end
1210
+ attr_writer :handle
1211
+
1212
+ # return/create a WindowsRemoteString
1213
+ def memory
1214
+ @memory ||= WindowsRemoteString.new(handle)
1215
+ end
1216
+ attr_writer :memory
1217
+
1218
+ def debugger
1219
+ @debugger ||= WinDebugger.new(@pid)
1220
+ end
1221
+ attr_writer :debugger
1222
+
1223
+ # returns the memory address size of the target process
1224
+ def addrsz
1225
+ @addrsz ||= if WinAPI.respond_to?(:iswow64process)
1226
+ byte = 0.chr*8
1227
+ if WinAPI.iswow64process(handle, byte)
1228
+ if byte != 0.chr*8
1229
+ 32 # target = wow64
1230
+ elsif WinAPI.iswow64process(WinAPI.getcurrentprocess, byte) and byte != 0.chr*8
1231
+ 64 # us = wow64, target is not
1232
+ else
1233
+ WinAPI.host_cpu.size
1234
+ end
1235
+ else
1236
+ WinAPI.host_cpu.size
1237
+ end
1238
+ end
1239
+ end
1240
+
1241
+ def modules
1242
+ WinOS.list_modules(@pid)
1243
+ end
1244
+
1245
+ def threads
1246
+ WinOS.list_threads(@pid)
1247
+ end
1248
+
1249
+ def heaps
1250
+ WinOS.list_heaps(@pid)
1251
+ end
1252
+
1253
+ # return a list of [addr_start, length, perms]
1254
+ def mappings
1255
+ addr = 0
1256
+ list = []
1257
+ info = WinAPI.alloc_c_struct("MEMORY_BASIC_INFORMATION#{addrsz}")
1258
+ path = [0xff].pack('C') * 512
1259
+
1260
+ hcache = heaps
1261
+
1262
+ while WinAPI.virtualqueryex(handle, addr, info, info.length) != 0
1263
+ addr += info.regionsize
1264
+ next unless info.state & WinAPI::MEM_COMMIT > 0
1265
+
1266
+ prot = {
1267
+ WinAPI::PAGE_NOACCESS => '---',
1268
+ WinAPI::PAGE_READONLY => 'r--',
1269
+ WinAPI::PAGE_READWRITE => 'rw-',
1270
+ WinAPI::PAGE_WRITECOPY => 'rw-',
1271
+ WinAPI::PAGE_EXECUTE => '--x',
1272
+ WinAPI::PAGE_EXECUTE_READ => 'r-x',
1273
+ WinAPI::PAGE_EXECUTE_READWRITE => 'rwx',
1274
+ WinAPI::PAGE_EXECUTE_WRITECOPY => 'rwx'
1275
+ }[info[:protect] & 0xff]
1276
+ prot << 'g' if info[:protect] & WinAPI::PAGE_GUARD > 0
1277
+ prot << 'p' if info[:type] & WinAPI::MEM_PRIVATE > 0
1278
+
1279
+ if h = hcache[info.baseaddress]
1280
+ a = []
1281
+ a << 'default' if h[:default]
1282
+ a << 'shared' if h[:shared]
1283
+ a << 'heap'
1284
+ #a << h[:flags].to_s(16)
1285
+ cmt = '[' + a.join(' ') + ']'
1286
+ elsif WinAPI.ntqueryvirtualmemory(handle, info.baseaddress, WinAPI::MEMORYMAPFILENAME, path, path.length, 0) == 0
1287
+ us = WinAPI.decode_c_struct('UNICODE_STRING', path)
1288
+ s = WinAPI.decode_c_ary('USHORT', us['Length']/2, WinAPI.memory_read(us['Buffer'], us['MaximumLength']))
1289
+ cmt = s.to_strz
1290
+ else
1291
+ cmt = ''
1292
+ end
1293
+
1294
+ list << [info.baseaddress, info.regionsize, prot, cmt]
1295
+ end
1296
+
1297
+ list
1298
+ end
1299
+
1300
+ def peb_base
1301
+ @peb_base ||=
1302
+ if WinAPI.respond_to?(:ntqueryinformationprocess)
1303
+ pinfo = WinAPI.alloc_c_struct('PROCESS_BASIC_INFORMATION')
1304
+ if WinAPI.ntqueryinformationprocess(handle, WinAPI::PROCESSBASICINFORMATION, pinfo, pinfo.length, 0) == 0
1305
+ pinfo.pebbaseaddress
1306
+ end
1307
+ else
1308
+ # pre-NT: all pebs should have the same addr
1309
+ WinAPI.new_func_asm('unsigned get_peb(void)', 'mov eax, fs:[30h] ret') { WinAPI.get_peb }
1310
+ end
1311
+ end
1312
+ attr_writer :peb_base
1313
+
1314
+ def terminate(exitcode=0)
1315
+ WinAPI.terminateprocess(handle, exitcode)
1316
+ end
1317
+ end
1318
+
1319
+ class Thread
1320
+ attr_accessor :tid
1321
+ attr_accessor :process
1322
+
1323
+ def initialize(tid, handle=nil, process=nil)
1324
+ @tid = tid
1325
+ @handle = handle
1326
+ @process = process
1327
+ end
1328
+
1329
+ def handle
1330
+ @handle ||= WinAPI.openthread(WinAPI::THREAD_ALL_ACCESS, 0, @tid)
1331
+ end
1332
+ attr_writer :handle
1333
+
1334
+ # return the address of the TEB for the target thread
1335
+ def teb_base
1336
+ @teb_base ||=
1337
+ if WinAPI.respond_to?(:ntqueryinformationthread)
1338
+ tinfo = WinAPI.alloc_c_struct('THREAD_BASIC_INFORMATION')
1339
+ if WinAPI.ntqueryinformationthread(handle, WinAPI::THREADBASICINFORMATION, tinfo, tinfo.length, 0) == 0
1340
+ tinfo.tebbaseaddress
1341
+ end
1342
+ else
1343
+ fs = context { |c| c[:fs] }
1344
+ ldte = WinAPI.alloc_c_struct('LDT_ENTRY')
1345
+ if WinAPI.getthreadselectorentry(handle, fs, ldte)
1346
+ ldte.baselow | (ldte.basemid << 16) | (ldte.basehi << 24)
1347
+ end
1348
+ end
1349
+ end
1350
+ attr_writer :teb_base
1351
+
1352
+ # increment the suspend count of the target thread - stop at >0
1353
+ def suspend
1354
+ if WinAPI.host_cpu.size == 64 and process and process.addrsz == 32
1355
+ WinAPI.wow64suspendthread(handle)
1356
+ else
1357
+ WinAPI.suspendthread(handle)
1358
+ end
1359
+ end
1360
+
1361
+ # decrease the suspend count of the target thread - runs at 0
1362
+ def resume
1363
+ WinAPI.resumethread(handle)
1364
+ end
1365
+
1366
+ def terminate(exitcode=0)
1367
+ WinAPI.terminatethread(handle, exitcode)
1368
+ end
1369
+
1370
+ # returns a Context object. Can be reused, refresh the values with #update (target thread must be suspended)
1371
+ # if a block is given, suspend the thread, update the context, yield it, and resume the thread
1372
+ def context
1373
+ @context ||= Context.new(self, :all)
1374
+ if block_given?
1375
+ suspend
1376
+ @context.update
1377
+ ret = yield @context
1378
+ resume
1379
+ ret
1380
+ else
1381
+ @context
1382
+ end
1383
+ end
1384
+ attr_writer :context
1385
+
1386
+ class Context
1387
+ def initialize(thread, kind=:all)
1388
+ @handle = thread.handle
1389
+ tg = thread.process ? thread.process.addrsz : 32
1390
+ case WinAPI.host_cpu.shortname
1391
+ when 'ia32', 'x64'; tg = ((tg == 32) ? 'ia32' : 'x64')
1392
+ else raise "unsupported architecture #{tg}"
1393
+ end
1394
+
1395
+ @getcontext = :getthreadcontext
1396
+ @setcontext = :setthreadcontext
1397
+ case tg
1398
+ when 'ia32'
1399
+ @context = WinAPI.alloc_c_struct('_CONTEXT_I386')
1400
+ @context.contextflags = WinAPI::CONTEXT_I386_ALL
1401
+ if WinAPI.host_cpu.shortname == 'x64'
1402
+ @getcontext = :wow64getthreadcontext
1403
+ @setcontext = :wow64setthreadcontext
1404
+ end
1405
+ when 'x64'
1406
+ @context = WinAPI.alloc_c_struct('_CONTEXT_AMD64')
1407
+ @context.contextflags = WinAPI::CONTEXT_AMD64_ALL
1408
+ end
1409
+ end
1410
+
1411
+ # update the context to reflect the current thread reg values
1412
+ # call only when the thread is suspended
1413
+ def update
1414
+ WinAPI.send(@getcontext, @handle, @context)
1415
+ end
1416
+
1417
+ def [](k)
1418
+ case k.to_s
1419
+ when /^[cdefgs]s$/i
1420
+ @context["seg#{k}"]
1421
+ when /^st(\d*)/i
1422
+ v = @context['st'][$1.to_i]
1423
+ buf = v.str[v.str_off, 10]
1424
+ # TODO check this, 'D' is 8byte wide
1425
+ buf.unpack('D')[0]
1426
+ when /^xmm(\d+)/i
1427
+ v = @context['xmm'][$1.to_i]
1428
+ (v.hi << 64) | v.lo
1429
+ when /^mmx?(\d+)/i
1430
+ @context['xmm'][$1.to_i].lo
1431
+ else
1432
+ @context[k]
1433
+ end
1434
+ end
1435
+
1436
+ def []=(k, v)
1437
+ case k.to_s
1438
+ when /^[cdefgs]s$/i
1439
+ @context["seg#{k}"] = v
1440
+ when /^st(\d*)/i
1441
+ # TODO check this, 'D' is 8byte wide
1442
+ buf = [v, 0, 0].pack('DCC')
1443
+ @context['st'][$1.to_i][0, 10] = buf
1444
+ when /^xmm(\d+)/i
1445
+ kk = @context['xmm'][$1.to_i]
1446
+ kk.lo = v & ((1<<64)-1)
1447
+ kk.hi = (v>>64) & ((1<<64)-1)
1448
+ when /^mmx?(\d+)/i
1449
+ @context['xmm'][$1.to_i].lo = v
1450
+ else
1451
+ @context[k] = v
1452
+ end
1453
+ WinAPI.send(@setcontext, @handle, @context)
1454
+ end
1455
+
1456
+ def method_missing(m, *a)
1457
+ if m.to_s[-1] == ?=
1458
+ super(m, *a) if a.length != 1
1459
+ send '[]=', m.to_s[0...-1], a[0]
1460
+ else
1461
+ super(m, *a) if a.length != 0
1462
+ send '[]', m
1463
+ end
1464
+ end
1465
+ end
1466
+ end
1467
+
1468
+ class << self
1469
+ # try to enable debug privilege in current process
1470
+ def get_debug_privilege
1471
+ # TODO use real structs / new_func_c
1472
+ htok = [0].pack('L')
1473
+ return if not WinAPI.openprocesstoken(WinAPI.getcurrentprocess(), WinAPI::TOKEN_ADJUST_PRIVILEGES | WinAPI::TOKEN_QUERY, htok)
1474
+ luid = [0, 0].pack('LL')
1475
+ return if not WinAPI.lookupprivilegevaluea(nil, WinAPI::SE_DEBUG_NAME, luid)
1476
+
1477
+ # priv.PrivilegeCount = 1;
1478
+ # priv.Privileges[0].Luid = luid;
1479
+ # priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1480
+ priv = luid.unpack('LL').unshift(1).push(WinAPI::SE_PRIVILEGE_ENABLED).pack('LLLL')
1481
+ return if not WinAPI.adjusttokenprivileges(htok.unpack('L').first, 0, priv, 0, nil, nil)
1482
+
1483
+ true
1484
+ end
1485
+
1486
+ # returns an array of Processes with pid/ppid/path filled
1487
+ def list_processes
1488
+ h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPPROCESS, 0)
1489
+ list = []
1490
+ pe = WinAPI.alloc_c_struct('PROCESSENTRY32', :dwsize => :size)
1491
+ return if not WinAPI.process32first(h, pe)
1492
+ loop do
1493
+ p = Process.new(pe.th32processid)
1494
+ p.ppid = pe.th32parentprocessid
1495
+ p.path = pe.szexefile.to_strz
1496
+ list << p if p.pid != 0
1497
+ break if WinAPI.process32next(h, pe) == 0
1498
+ end
1499
+ WinAPI.closehandle(h)
1500
+ list
1501
+ end
1502
+
1503
+ # retrieve the list of Modules for a process with addr/size/path filled
1504
+ def list_modules(pid)
1505
+ h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPMODULE, pid)
1506
+ return [] if h == WinAPI::INVALID_HANDLE_VALUE
1507
+ list = []
1508
+ me = WinAPI.alloc_c_struct('MODULEENTRY32', :dwsize => :size)
1509
+ return [] if not WinAPI.module32first(h, me)
1510
+ loop do
1511
+ m = Process::Module.new
1512
+ m.addr = me.modbaseaddr
1513
+ m.size = me.modbasesize
1514
+ m.path = me.szexepath.to_strz
1515
+ list << m
1516
+ break if WinAPI.module32next(h, me) == 0
1517
+ end
1518
+ WinAPI.closehandle(h)
1519
+ list
1520
+ end
1521
+
1522
+ # returns the list of thread ids of the system, optionally filtering by pid
1523
+ def list_threads(pid=nil)
1524
+ h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPTHREAD, 0)
1525
+ list = []
1526
+ te = WinAPI.alloc_c_struct('THREADENTRY32', :dwsize => :size)
1527
+ return [] if not WinAPI.thread32first(h, te)
1528
+ loop do
1529
+ list << te.th32threadid if not pid or te.th32ownerprocessid == pid
1530
+ break if WinAPI.thread32next(h, te) == 0
1531
+ end
1532
+ WinAPI.closehandle(h)
1533
+ list
1534
+ end
1535
+
1536
+ # returns the heaps of the process, from a toolhelp snapshot SNAPHEAPLIST
1537
+ # this is a hash
1538
+ # heap_addr => { :flags => integer (heap flags)
1539
+ # :shared => bool (from flags)
1540
+ # :default => bool (from flags) }
1541
+ def list_heaps(pid)
1542
+ h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPHEAPLIST, pid)
1543
+ return [] if h == WinAPI::INVALID_HANDLE_VALUE
1544
+ ret = {}
1545
+ he = WinAPI.alloc_c_struct('HEAPLIST32', :dwsize => :size)
1546
+ return [] if not WinAPI.heap32listfirst(h, he)
1547
+ loop do
1548
+ hash = ret[he.th32heapid] = { :flags => he.dwflags }
1549
+ hash[:default] = true if hash[:flags] & WinAPI::HF32_DEFAULT == WinAPI::HF32_DEFAULT
1550
+ hash[:shared] = true if hash[:flags] & WinAPI::HF32_SHARED == WinAPI::HF32_SHARED
1551
+ # TODO there are lots of other flags in there ! like 0x1000 / 0x8000
1552
+ break if WinAPI.heap32listnext(h, he) == 0
1553
+ end
1554
+ WinAPI.closehandle(h)
1555
+ ret
1556
+ end
1557
+
1558
+
1559
+ # create a debugger for the target pid/path
1560
+ def create_debugger(path)
1561
+ WinDebugger.new(path)
1562
+ end
1563
+
1564
+ # Injects a shellcode into the memory space of targetproc
1565
+ # target is a WinOS::Process
1566
+ # shellcode may be a String (raw shellcode) or an EncodedData
1567
+ # With an EncodedData, unresolved relocations are solved using
1568
+ # exports of modules from the target address space ; also the
1569
+ # shellcode need not be position-independant.
1570
+ def inject_shellcode(target, shellcode)
1571
+ raise 'cannot open target memory' if not remote_mem = target.memory
1572
+ return if not injectaddr = WinAPI.virtualallocex(target.handle, 0, shellcode.length,
1573
+ WinAPI::MEM_COMMIT | WinAPI::MEM_RESERVE, WinAPI::PAGE_EXECUTE_READWRITE)
1574
+ puts 'remote buffer at %x' % injectaddr if $VERBOSE
1575
+
1576
+ if shellcode.kind_of? EncodedData
1577
+ fixup_shellcode_relocs(shellcode, target, remote_mem)
1578
+ shellcode.fixup! shellcode.binding(injectaddr)
1579
+ r = shellcode.reloc.values.map { |r_| r_.target }
1580
+ raise "unresolved shellcode relocs #{r.join(', ')}" if not r.empty?
1581
+ shellcode = shellcode.data
1582
+ end
1583
+
1584
+ # inject the shellcode
1585
+ remote_mem[injectaddr, shellcode.length] = shellcode
1586
+
1587
+ injectaddr
1588
+ end
1589
+
1590
+ def fixup_shellcode_relocs(shellcode, target, remote_mem)
1591
+ ext = shellcode.reloc_externals
1592
+ binding = {}
1593
+ while e = ext.pop
1594
+ next if binding[e]
1595
+ next if not lib = WindowsExports::EXPORT[e] # XXX could scan all exports... LoadLibrary ftw
1596
+ next if not m = target.modules.find { |m_| m_.path.downcase.include? lib.downcase }
1597
+ lib = LoadedPE.load(remote_mem[m.addr, 0x1000_0000])
1598
+ lib.decode_header
1599
+ lib.decode_exports
1600
+ lib.export.exports.each { |e_|
1601
+ next if not e_.name or not e_.target
1602
+ binding[e_.name] = m.addr + lib.label_rva(e_.target)
1603
+ }
1604
+ shellcode.fixup! binding
1605
+ end
1606
+ end
1607
+
1608
+ # creates a new thread in the target process, with the specified start address
1609
+ def createthread(target, startaddr)
1610
+ WinAPI.createremotethread(target.handle, 0, 0, startaddr, 0, 0, 0)
1611
+ end
1612
+
1613
+ # calls inject_shellcode and createthread
1614
+ def inject_run_shellcode(target, shellcode)
1615
+ raise "failed to inject shellcode" if not addr = inject_shellcode(target, shellcode)
1616
+ createthread(target, addr)
1617
+ end
1618
+
1619
+ # returns a Process associated to the process handle
1620
+ def open_process_handle(h)
1621
+ pid = WinAPI.getprocessid(h) rescue 0
1622
+ Process.new(pid, h)
1623
+ end
1624
+
1625
+ # returns the Process associated to pid if it is alive
1626
+ def open_process(pid)
1627
+ Process.new(pid) if check_process(pid)
1628
+ end
1629
+
1630
+ # returns true if the process pid exists and we can open it with QUERY_INFORMATION
1631
+ def check_process(pid)
1632
+ if h = WinAPI.openprocess(WinAPI::PROCESS_QUERY_INFORMATION, 0, pid)
1633
+ WinAPI.closehandle(h)
1634
+ true
1635
+ end
1636
+ end
1637
+
1638
+ # returns the Thread associated to a tid if it is alive
1639
+ def open_thread(tid)
1640
+ Thread.new(tid) if check_tid(tid)
1641
+ end
1642
+
1643
+ # check if the thread is alive and can be read with QUERY_INFO
1644
+ # and optionally if it belongs to pid
1645
+ def check_tid(tid, pid=nil)
1646
+ if h = WinAPI.openthread(WinAPI::THREAD_QUERY_INFORMATION, 0, tid)
1647
+ WinAPI.closehandle(h)
1648
+ not pid or list_threads(pid).include?(tid)
1649
+ end
1650
+ end
1651
+
1652
+ end # class << self
1653
+ end
1654
+
1655
+ class WindowsRemoteString < VirtualString
1656
+ def self.open_pid(pid, access = nil)
1657
+ if access
1658
+ handle = WinAPI.openprocess(access, 0, pid)
1659
+ else
1660
+ handle = WinAPI.openprocess(WinAPI::PROCESS_ALL_ACCESS, 0, pid)
1661
+ if not handle
1662
+ puts "cannot openprocess ALL_ACCESS pid #{pid}, try ro" if $VERBOSE
1663
+ handle = WinAPI.openprocess(WinAPI::PROCESS_VM_READ, 0, pid)
1664
+ end
1665
+ end
1666
+ raise "OpenProcess(#{pid}): #{WinAPI.last_error_msg}" if not handle
1667
+
1668
+ new(handle)
1669
+ end
1670
+
1671
+ attr_accessor :handle
1672
+
1673
+ # returns a virtual string proxying the specified process memory range
1674
+ # reads are cached (4096 aligned bytes read at once)
1675
+ # writes are done directly (if handle has appropriate privileges)
1676
+ def initialize(handle, addr_start=0, length=nil)
1677
+ @handle = handle
1678
+ length ||= 1 << (WinOS.open_process_handle(@handle).addrsz rescue 32)
1679
+ super(addr_start, length)
1680
+ end
1681
+
1682
+ def dup(addr = @addr_start, len = @length)
1683
+ self.class.new(@handle, addr, len)
1684
+ end
1685
+
1686
+ def rewrite_at(addr, data)
1687
+ WinAPI.writeprocessmemory(@handle, addr, data, data.length, nil)
1688
+ end
1689
+
1690
+ def get_page(addr, len=@pagelength)
1691
+ page = [0].pack('C')*len
1692
+ return if WinAPI.readprocessmemory(@handle, addr, page, len, 0) == 0
1693
+ page
1694
+ end
1695
+ end
1696
+
1697
+ # this class implements a high-level API over the Windows debugging primitives
1698
+ class WinDebugger < Debugger
1699
+ attr_accessor :os_process, :os_thread,
1700
+ :auto_fix_fs_bug,
1701
+ # is current exception handled? (arg to pass to continuedbgevt)
1702
+ :continuecode
1703
+
1704
+ attr_accessor :callback_unloadlibrary, :callback_debugstring, :callback_ripevent
1705
+
1706
+ def initialize(pidpath=nil)
1707
+ super()
1708
+ @pid_stuff_list << :os_process
1709
+ @tid_stuff_list << :os_thread << :ctx << :continuecode
1710
+
1711
+ @auto_fix_fs_bug = false
1712
+
1713
+ return if not pidpath
1714
+
1715
+ begin
1716
+ npid = Integer(pidpath)
1717
+ attach(npid)
1718
+ rescue ArgumentError
1719
+ create_process(pidpath)
1720
+ end
1721
+
1722
+ check_target until pid
1723
+ end
1724
+
1725
+ def shortname; 'windbg'; end
1726
+
1727
+ def attach(npid)
1728
+ WinAPI.debugactiveprocess(npid)
1729
+ WinAPI.debugsetprocesskillonexit(0) if WinAPI.respond_to?(:debugsetprocesskillonexit)
1730
+ 100.times {
1731
+ check_target
1732
+ break if pid
1733
+ }
1734
+ raise "attach failed" if not pid
1735
+ end
1736
+
1737
+ def create_process(target)
1738
+ startupinfo = WinAPI.alloc_c_struct('STARTUPINFOA', :cb => :size)
1739
+ processinfo = WinAPI.alloc_c_struct('PROCESS_INFORMATION')
1740
+ flags = WinAPI::DEBUG_PROCESS
1741
+ flags |= WinAPI::DEBUG_ONLY_THIS_PROCESS if not trace_children
1742
+ target = target.dup if target.frozen? # eg ARGV
1743
+ h = WinAPI.createprocessa(nil, target, nil, nil, 0, flags, nil, nil, startupinfo, processinfo)
1744
+ raise "CreateProcess: #{WinAPI.last_error_msg}" if not h
1745
+
1746
+ set_context(processinfo.dwprocessid, processinfo.dwthreadid)
1747
+ @os_process = WinOS::Process.new(processinfo.dwprocessid, processinfo.hprocess)
1748
+ @os_thread = WinOS::Thread.new(processinfo.dwthreadid, processinfo.hthread, @os_process)
1749
+ initialize_osprocess
1750
+ end
1751
+
1752
+ # called whenever we receive a handle to a new process being debugged, after initialisation of @os_process
1753
+ def initialize_osprocess
1754
+ initialize_cpu
1755
+ initialize_memory
1756
+ initialize_disassembler
1757
+ end
1758
+
1759
+ def initialize_newpid
1760
+ raise "non-existing pid #@pid" if pid and not WinOS.check_process(@pid)
1761
+ super()
1762
+ # os_process etc wait for CREATE_THREAD_DBGEVT
1763
+ end
1764
+
1765
+ def initialize_newtid
1766
+ super()
1767
+ # os_thread etc wait for CREATE_THREAD_DBGEVT
1768
+ @continuecode = WinAPI::DBG_CONTINUE #WinAPI::DBG_EXCEPTION_NOT_HANDLED
1769
+ end
1770
+
1771
+ def initialize_cpu
1772
+ # wait until we receive the CREATE_PROCESS_DBGEVT message
1773
+ return if not @os_process
1774
+ case WinAPI.host_cpu.shortname
1775
+ when 'ia32', 'x64'
1776
+ @cpu = Ia32.new(os_process.addrsz)
1777
+ else
1778
+ raise 'unsupported architecture'
1779
+ end
1780
+ end
1781
+
1782
+ def initialize_memory
1783
+ return if not @os_process
1784
+ @memory = os_process.memory
1785
+ end
1786
+
1787
+ def mappings
1788
+ os_process.mappings
1789
+ end
1790
+
1791
+ def modules
1792
+ os_process.modules
1793
+ end
1794
+
1795
+ def list_processes
1796
+ WinOS.list_processes
1797
+ end
1798
+
1799
+ def list_threads
1800
+ os_process.threads
1801
+ end
1802
+
1803
+ def check_pid(pid)
1804
+ WinOS.check_process(pid)
1805
+ end
1806
+
1807
+ def check_tid(tid)
1808
+ # dont raise() on the first set_context when os_proc is not set yet
1809
+ return true if not os_process
1810
+ super(tid)
1811
+ end
1812
+
1813
+ def ctx
1814
+ if not @ctx
1815
+ # swapin_tid => gui.swapin_tid => getreg before we init os_thread in EventCreateThread
1816
+ return Hash.new(0) if not os_thread
1817
+ @ctx = os_thread.context
1818
+ @ctx.update
1819
+ end
1820
+ @ctx
1821
+ end
1822
+
1823
+ def invalidate
1824
+ @ctx = nil
1825
+ super()
1826
+ end
1827
+
1828
+ def get_reg_value(r)
1829
+ ctx[r]
1830
+ end
1831
+
1832
+ def set_reg_value(r, v)
1833
+ ctx[r] = v
1834
+ end
1835
+
1836
+ def do_continue(*a)
1837
+ @cpu.dbg_disable_singlestep(self)
1838
+ WinAPI.continuedebugevent(@pid, @tid, @continuecode)
1839
+ end
1840
+
1841
+ def do_singlestep(*a)
1842
+ @cpu.dbg_enable_singlestep(self)
1843
+ WinAPI.continuedebugevent(@pid, @tid, @continuecode)
1844
+ end
1845
+
1846
+ def update_dbgev(ev)
1847
+ # XXX ev is static, copy all necessary values before yielding to something that may call check_target
1848
+ set_context ev.dwprocessid, ev.dwthreadid
1849
+ invalidate
1850
+ @continuecode = WinAPI::DBG_CONTINUE
1851
+
1852
+ # XXX reinterpret ev as struct32/64 depending on os_process.addrsz ?
1853
+ case ev.dwdebugeventcode
1854
+ when WinAPI::EXCEPTION_DEBUG_EVENT
1855
+ st = ev.exception
1856
+ str = st.exceptionrecord
1857
+ stf = st.dwfirstchance # non-zero = first chance
1858
+
1859
+ @state = :stopped
1860
+ @info = "exception"
1861
+
1862
+ # DWORD ExceptionCode;
1863
+ # DWORD ExceptionFlags;
1864
+ # struct _EXCEPTION_RECORD *ExceptionRecord;
1865
+ # PVOID ExceptionAddress;
1866
+ # DWORD NumberParameters;
1867
+ # ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
1868
+ case str.exceptioncode
1869
+ when WinAPI::STATUS_ACCESS_VIOLATION
1870
+ if @auto_fix_fs_bug and ctx.fs != 0x3b
1871
+ # fix bug in xpsp1 where fs would get a random value in a debugee
1872
+ log "wdbg: #{pid}:#{tid} fix fs bug" if $DEBUG
1873
+ ctx.fs = 0x3b
1874
+ resume_badbreak
1875
+ return
1876
+ end
1877
+ mode = case str.exceptioninformation[0]
1878
+ when 0; :r
1879
+ when 1; :w
1880
+ when 8; :x
1881
+ end
1882
+ addr = str.exceptioninformation[1]
1883
+ evt_exception(:type => 'access violation', :st => str, :firstchance => stf,
1884
+ :fault_addr => addr, :fault_access => mode)
1885
+ when WinAPI::STATUS_BREAKPOINT
1886
+ # we must ack ntdll interrupts on process start
1887
+ # but we should not mask process-generated exceptions by default..
1888
+ evt_bpx
1889
+ when WinAPI::STATUS_SINGLE_STEP
1890
+ evt_hwbp_singlestep
1891
+ else
1892
+ @status_name ||= WinAPI.cp.lexer.definition.keys.grep(/^STATUS_/).
1893
+ sort.inject({}) { |h, c| h.update WinAPI.const_get(c) => c }
1894
+ type = @status_name[str.exceptioncode] || str.exceptioncode.to_s(16)
1895
+ evt_exception(:type => type, :st => str, :firstchance => stf)
1896
+ end
1897
+
1898
+ when WinAPI::CREATE_THREAD_DEBUG_EVENT
1899
+ st = ev.createthread
1900
+ @os_thread ||= WinOS::Thread.new(@tid, st.hthread, os_process)
1901
+ @os_thread.teb_base = st.lpthreadlocalbase if st.lpthreadlocalbase.to_i != 0
1902
+ evt_newthread(:st => st)
1903
+
1904
+ when WinAPI::CREATE_PROCESS_DEBUG_EVENT
1905
+ # XXX 32 vs 64 struct undecidable before we get hprocess..
1906
+ st = ev.createprocess
1907
+ if not @os_process
1908
+ @os_process = WinOS::Process.new(@pid, st.hprocess)
1909
+ @os_thread ||= WinOS::Thread.new(@tid, st.hthread, os_process)
1910
+ initialize_osprocess
1911
+ else
1912
+ @os_thread ||= WinOS::Thread.new(@tid, st.hthread, os_process)
1913
+ end
1914
+ @os_thread.teb_base = st.lpthreadlocalbase if st.lpthreadlocalbase.to_i != 0
1915
+ hfile = st.hfile
1916
+ evt_newprocess(:st => st)
1917
+ WinAPI.closehandle(hfile)
1918
+
1919
+ when WinAPI::EXIT_THREAD_DEBUG_EVENT
1920
+ st = ev.exitthread
1921
+ evt_endthread(:exitcode => st.dwexitcode)
1922
+
1923
+ when WinAPI::EXIT_PROCESS_DEBUG_EVENT
1924
+ st = ev.exitprocess
1925
+ evt_endprocess(:exitcode => st.dwexitcode)
1926
+
1927
+ when WinAPI::LOAD_DLL_DEBUG_EVENT
1928
+ st = ev.loaddll
1929
+ hfile = st.hfile
1930
+ evt_loadlibrary(:address => st.lpbaseofdll, :st => st)
1931
+ WinAPI.closehandle(hfile)
1932
+
1933
+ when WinAPI::UNLOAD_DLL_DEBUG_EVENT
1934
+ st = ev.unloaddll
1935
+ evt_unloadlibrary(:address => st.lpbaseofdll)
1936
+
1937
+ when WinAPI::OUTPUT_DEBUG_STRING_EVENT
1938
+ st = ev.debugstring
1939
+ str = WinAPI.decode_c_ary("__int#{st.funicode != 0 ? 16 : 8}", st.ndebugstringlength, @memory, st.lpdebugstringdata) if st.lpdebugstringdata
1940
+ str = str.to_array.pack('C*') rescue str.to_array.pack('v*')
1941
+ evt_debugstring(:string => str, :st => str)
1942
+
1943
+ when WinAPI::RIP_EVENT
1944
+ st = ev.ripinfo
1945
+ evt_ripevent(:st => st)
1946
+ end
1947
+ end
1948
+
1949
+ def evt_debugstring(info={})
1950
+ @state = :stopped
1951
+ @info = "debugstring"
1952
+
1953
+ log "Debugstring: #{info[:string].inspect}"
1954
+
1955
+ callback_debugstring[info] if callback_debugstring
1956
+
1957
+ # allow callback to skip this call to continue() by setting info[:nocontinue] = true
1958
+ continue unless info[:nocontinue]
1959
+ end
1960
+
1961
+ def evt_unloadlibrary(info={})
1962
+ @state = :stopped
1963
+ @info = "unload library"
1964
+
1965
+ callback_unloadlibrary[info] if callback_unloadlibrary
1966
+
1967
+ continue unless info[:nocontinue]
1968
+ end
1969
+
1970
+ def evt_ripevent(info={})
1971
+ @state = :stopped
1972
+ @info = "rip_event" # wtf?
1973
+
1974
+ callback_ripevent[info] if callback_ripevent
1975
+
1976
+ continue unless info[:nocontinue]
1977
+ end
1978
+
1979
+ def do_check_target
1980
+ do_waitfordebug(0)
1981
+ end
1982
+
1983
+ def do_wait_target
1984
+ do_waitfordebug(WinAPI::INFINITE)
1985
+ end
1986
+
1987
+ def do_waitfordebug(timeout)
1988
+ @dbg_eventstruct ||= WinAPI.alloc_c_struct('_DEBUG_EVENT')
1989
+ if WinAPI.waitfordebugevent(@dbg_eventstruct, timeout) != 0
1990
+ update_dbgev(@dbg_eventstruct)
1991
+ end
1992
+ end
1993
+
1994
+ def break
1995
+ return if @state != :running
1996
+ if WinAPI.respond_to? :debugbreakprocess
1997
+ WinAPI.debugbreakprocess(os_process.handle)
1998
+ else
1999
+ suspend
2000
+ end
2001
+ end
2002
+
2003
+ def suspend
2004
+ os_thread.suspend
2005
+ @state = :stopped
2006
+ @info = 'thread suspended'
2007
+ end
2008
+
2009
+ def detach
2010
+ del_all_breakpoints
2011
+ if WinAPI.respond_to? :debugactiveprocessstop
2012
+ WinAPI.debugactiveprocessstop(@pid)
2013
+ else
2014
+ raise 'detach not supported'
2015
+ end
2016
+ del_pid
2017
+ end
2018
+
2019
+ def kill(exitcode=0)
2020
+ os_process.terminate(exitcode)
2021
+ end
2022
+
2023
+ def pass_current_exception(doit = true)
2024
+ @continuecode = (doit ? WinAPI::DBG_EXCEPTION_NOT_HANDLED : WinAPI::DBG_CONTINUE)
2025
+ end
2026
+ end
2027
+ end