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.
- data/BUGS +11 -0
- data/CREDITS +17 -0
- data/README +270 -0
- data/TODO +114 -0
- data/doc/code_organisation.txt +146 -0
- data/doc/const_missing.txt +16 -0
- data/doc/core_classes.txt +75 -0
- data/doc/feature_list.txt +53 -0
- data/doc/index.txt +59 -0
- data/doc/install_notes.txt +170 -0
- data/doc/style.css +3 -0
- data/doc/use_cases.txt +18 -0
- data/lib/metasm.rb +80 -0
- data/lib/metasm/arm.rb +12 -0
- data/lib/metasm/arm/debug.rb +39 -0
- data/lib/metasm/arm/decode.rb +167 -0
- data/lib/metasm/arm/encode.rb +77 -0
- data/lib/metasm/arm/main.rb +75 -0
- data/lib/metasm/arm/opcodes.rb +177 -0
- data/lib/metasm/arm/parse.rb +130 -0
- data/lib/metasm/arm/render.rb +55 -0
- data/lib/metasm/compile_c.rb +1457 -0
- data/lib/metasm/dalvik.rb +8 -0
- data/lib/metasm/dalvik/decode.rb +196 -0
- data/lib/metasm/dalvik/main.rb +60 -0
- data/lib/metasm/dalvik/opcodes.rb +366 -0
- data/lib/metasm/decode.rb +213 -0
- data/lib/metasm/decompile.rb +2659 -0
- data/lib/metasm/disassemble.rb +2068 -0
- data/lib/metasm/disassemble_api.rb +1280 -0
- data/lib/metasm/dynldr.rb +1329 -0
- data/lib/metasm/encode.rb +333 -0
- data/lib/metasm/exe_format/a_out.rb +194 -0
- data/lib/metasm/exe_format/autoexe.rb +82 -0
- data/lib/metasm/exe_format/bflt.rb +189 -0
- data/lib/metasm/exe_format/coff.rb +455 -0
- data/lib/metasm/exe_format/coff_decode.rb +901 -0
- data/lib/metasm/exe_format/coff_encode.rb +1078 -0
- data/lib/metasm/exe_format/dex.rb +457 -0
- data/lib/metasm/exe_format/dol.rb +145 -0
- data/lib/metasm/exe_format/elf.rb +923 -0
- data/lib/metasm/exe_format/elf_decode.rb +979 -0
- data/lib/metasm/exe_format/elf_encode.rb +1375 -0
- data/lib/metasm/exe_format/macho.rb +827 -0
- data/lib/metasm/exe_format/main.rb +228 -0
- data/lib/metasm/exe_format/mz.rb +164 -0
- data/lib/metasm/exe_format/nds.rb +172 -0
- data/lib/metasm/exe_format/pe.rb +437 -0
- data/lib/metasm/exe_format/serialstruct.rb +246 -0
- data/lib/metasm/exe_format/shellcode.rb +114 -0
- data/lib/metasm/exe_format/xcoff.rb +167 -0
- data/lib/metasm/gui.rb +23 -0
- data/lib/metasm/gui/cstruct.rb +373 -0
- data/lib/metasm/gui/dasm_coverage.rb +199 -0
- data/lib/metasm/gui/dasm_decomp.rb +369 -0
- data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
- data/lib/metasm/gui/dasm_graph.rb +1354 -0
- data/lib/metasm/gui/dasm_hex.rb +543 -0
- data/lib/metasm/gui/dasm_listing.rb +599 -0
- data/lib/metasm/gui/dasm_main.rb +906 -0
- data/lib/metasm/gui/dasm_opcodes.rb +291 -0
- data/lib/metasm/gui/debug.rb +1228 -0
- data/lib/metasm/gui/gtk.rb +884 -0
- data/lib/metasm/gui/qt.rb +495 -0
- data/lib/metasm/gui/win32.rb +3004 -0
- data/lib/metasm/gui/x11.rb +621 -0
- data/lib/metasm/ia32.rb +14 -0
- data/lib/metasm/ia32/compile_c.rb +1523 -0
- data/lib/metasm/ia32/debug.rb +193 -0
- data/lib/metasm/ia32/decode.rb +1167 -0
- data/lib/metasm/ia32/decompile.rb +564 -0
- data/lib/metasm/ia32/encode.rb +314 -0
- data/lib/metasm/ia32/main.rb +233 -0
- data/lib/metasm/ia32/opcodes.rb +872 -0
- data/lib/metasm/ia32/parse.rb +327 -0
- data/lib/metasm/ia32/render.rb +91 -0
- data/lib/metasm/main.rb +1193 -0
- data/lib/metasm/mips.rb +11 -0
- data/lib/metasm/mips/compile_c.rb +7 -0
- data/lib/metasm/mips/decode.rb +253 -0
- data/lib/metasm/mips/encode.rb +51 -0
- data/lib/metasm/mips/main.rb +72 -0
- data/lib/metasm/mips/opcodes.rb +443 -0
- data/lib/metasm/mips/parse.rb +51 -0
- data/lib/metasm/mips/render.rb +43 -0
- data/lib/metasm/os/gnu_exports.rb +270 -0
- data/lib/metasm/os/linux.rb +1112 -0
- data/lib/metasm/os/main.rb +1686 -0
- data/lib/metasm/os/remote.rb +527 -0
- data/lib/metasm/os/windows.rb +2027 -0
- data/lib/metasm/os/windows_exports.rb +745 -0
- data/lib/metasm/parse.rb +876 -0
- data/lib/metasm/parse_c.rb +3938 -0
- data/lib/metasm/pic16c/decode.rb +42 -0
- data/lib/metasm/pic16c/main.rb +17 -0
- data/lib/metasm/pic16c/opcodes.rb +68 -0
- data/lib/metasm/ppc.rb +11 -0
- data/lib/metasm/ppc/decode.rb +264 -0
- data/lib/metasm/ppc/decompile.rb +251 -0
- data/lib/metasm/ppc/encode.rb +51 -0
- data/lib/metasm/ppc/main.rb +129 -0
- data/lib/metasm/ppc/opcodes.rb +410 -0
- data/lib/metasm/ppc/parse.rb +52 -0
- data/lib/metasm/preprocessor.rb +1277 -0
- data/lib/metasm/render.rb +130 -0
- data/lib/metasm/sh4.rb +8 -0
- data/lib/metasm/sh4/decode.rb +336 -0
- data/lib/metasm/sh4/main.rb +292 -0
- data/lib/metasm/sh4/opcodes.rb +381 -0
- data/lib/metasm/x86_64.rb +12 -0
- data/lib/metasm/x86_64/compile_c.rb +1025 -0
- data/lib/metasm/x86_64/debug.rb +59 -0
- data/lib/metasm/x86_64/decode.rb +268 -0
- data/lib/metasm/x86_64/encode.rb +264 -0
- data/lib/metasm/x86_64/main.rb +135 -0
- data/lib/metasm/x86_64/opcodes.rb +118 -0
- data/lib/metasm/x86_64/parse.rb +68 -0
- data/misc/bottleneck.rb +61 -0
- data/misc/cheader-findpppath.rb +58 -0
- data/misc/hexdiff.rb +74 -0
- data/misc/hexdump.rb +55 -0
- data/misc/metasm-all.rb +13 -0
- data/misc/objdiff.rb +47 -0
- data/misc/objscan.rb +40 -0
- data/misc/pdfparse.rb +661 -0
- data/misc/ppc_pdf2oplist.rb +192 -0
- data/misc/tcp_proxy_hex.rb +84 -0
- data/misc/txt2html.rb +440 -0
- data/samples/a.out.rb +31 -0
- data/samples/asmsyntax.rb +77 -0
- data/samples/bindiff.rb +555 -0
- data/samples/compilation-steps.rb +49 -0
- data/samples/cparser_makestackoffset.rb +55 -0
- data/samples/dasm-backtrack.rb +38 -0
- data/samples/dasmnavig.rb +318 -0
- data/samples/dbg-apihook.rb +228 -0
- data/samples/dbghelp.rb +143 -0
- data/samples/disassemble-gui.rb +102 -0
- data/samples/disassemble.rb +133 -0
- data/samples/dump_upx.rb +95 -0
- data/samples/dynamic_ruby.rb +1929 -0
- data/samples/elf_list_needed.rb +46 -0
- data/samples/elf_listexports.rb +33 -0
- data/samples/elfencode.rb +25 -0
- data/samples/exeencode.rb +128 -0
- data/samples/factorize-headers-elfimports.rb +77 -0
- data/samples/factorize-headers-peimports.rb +109 -0
- data/samples/factorize-headers.rb +43 -0
- data/samples/gdbclient.rb +583 -0
- data/samples/generate_libsigs.rb +102 -0
- data/samples/hotfix_gtk_dbg.rb +59 -0
- data/samples/install_win_env.rb +78 -0
- data/samples/lindebug.rb +924 -0
- data/samples/linux_injectsyscall.rb +95 -0
- data/samples/machoencode.rb +31 -0
- data/samples/metasm-shell.rb +91 -0
- data/samples/pe-hook.rb +69 -0
- data/samples/pe-ia32-cpuid.rb +203 -0
- data/samples/pe-mips.rb +35 -0
- data/samples/pe-shutdown.rb +78 -0
- data/samples/pe-testrelocs.rb +51 -0
- data/samples/pe-testrsrc.rb +24 -0
- data/samples/pe_listexports.rb +31 -0
- data/samples/peencode.rb +19 -0
- data/samples/peldr.rb +494 -0
- data/samples/preprocess-flatten.rb +19 -0
- data/samples/r0trace.rb +308 -0
- data/samples/rubstop.rb +399 -0
- data/samples/scan_pt_gnu_stack.rb +54 -0
- data/samples/scanpeexports.rb +62 -0
- data/samples/shellcode-c.rb +40 -0
- data/samples/shellcode-dynlink.rb +146 -0
- data/samples/source.asm +34 -0
- data/samples/struct_offset.rb +47 -0
- data/samples/testpe.rb +32 -0
- data/samples/testraw.rb +45 -0
- data/samples/win32genloader.rb +132 -0
- data/samples/win32hooker-advanced.rb +169 -0
- data/samples/win32hooker.rb +96 -0
- data/samples/win32livedasm.rb +33 -0
- data/samples/win32remotescan.rb +133 -0
- data/samples/wintrace.rb +92 -0
- data/tests/all.rb +8 -0
- data/tests/dasm.rb +39 -0
- data/tests/dynldr.rb +35 -0
- data/tests/encodeddata.rb +132 -0
- data/tests/ia32.rb +82 -0
- data/tests/mips.rb +116 -0
- data/tests/parse_c.rb +239 -0
- data/tests/preprocessor.rb +269 -0
- data/tests/x86_64.rb +62 -0
- metadata +255 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
3
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
4
|
+
#
|
|
5
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# this file takes preprocessor files as arguments
|
|
9
|
+
# it preprocesses their content and dump the result to stdout
|
|
10
|
+
# it also dumps all macro definitions
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
require 'metasm/preprocessor'
|
|
14
|
+
|
|
15
|
+
p = Metasm::Preprocessor.new
|
|
16
|
+
p.feed(ARGF.read)
|
|
17
|
+
raw = p.dump
|
|
18
|
+
puts p.dump_macros(p.definition.keys, false)
|
|
19
|
+
puts raw
|
data/samples/r0trace.rb
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
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
|
+
# This creates/uses a ring0 driver for tracing a program
|
|
7
|
+
# x86/windows/singlecore only
|
|
8
|
+
# the scripts allows interacting with the driver
|
|
9
|
+
# you still have to set the target thread in singlestep mode (eg using Debugger)
|
|
10
|
+
|
|
11
|
+
# How does it work:
|
|
12
|
+
# the driver hooks the IDT int1/int0f (NOT SMP PROOF)
|
|
13
|
+
# on int1, it logs eip in a memory buffer
|
|
14
|
+
# on int0f, it returns the memory buffer (memcopy to mem pointed by eax)
|
|
15
|
+
# the buffer 1st dword is the number of used dwords in the buffer (0 = empty)
|
|
16
|
+
# on overflow, eips are lost
|
|
17
|
+
|
|
18
|
+
require 'metasm'
|
|
19
|
+
include Metasm
|
|
20
|
+
|
|
21
|
+
$drv = 'r0trace.sys'
|
|
22
|
+
# size of the eip buffer (in dwords)
|
|
23
|
+
TRACE_BUF_SZ = 4*1024*1024-4
|
|
24
|
+
if not File.exist? $drv
|
|
25
|
+
PE.assemble(Ia32.new, <<EOS).encode_file($drv, 'kmod')
|
|
26
|
+
#define bufsz #{TRACE_BUF_SZ}
|
|
27
|
+
|
|
28
|
+
.data
|
|
29
|
+
oldi1 dd 0,0
|
|
30
|
+
oldi15 dd 0,0
|
|
31
|
+
buf dd bufsz dup(?)
|
|
32
|
+
|
|
33
|
+
.text
|
|
34
|
+
.entrypoint
|
|
35
|
+
mov eax, [esp+4]
|
|
36
|
+
mov dword ptr [eax+0x34], unload // drv->DriverUnload
|
|
37
|
+
call setup_idt
|
|
38
|
+
xor eax, eax
|
|
39
|
+
mov [buf], eax // buf used size
|
|
40
|
+
ret
|
|
41
|
+
|
|
42
|
+
unload:
|
|
43
|
+
// XXX smp
|
|
44
|
+
call get_idt
|
|
45
|
+
push [oldi1+4]
|
|
46
|
+
push [oldi1]
|
|
47
|
+
pop [eax+8*1]
|
|
48
|
+
pop [eax+8*1+4]
|
|
49
|
+
push [oldi15+4]
|
|
50
|
+
push [oldi15]
|
|
51
|
+
pop [eax+8*15]
|
|
52
|
+
pop [eax+8*15+4]
|
|
53
|
+
xor eax, eax
|
|
54
|
+
ret
|
|
55
|
+
|
|
56
|
+
setup_idt:
|
|
57
|
+
// XXX smp
|
|
58
|
+
call get_idt
|
|
59
|
+
push [eax+8*1]
|
|
60
|
+
push [eax+8*1+4]
|
|
61
|
+
pop [oldi1+4]
|
|
62
|
+
pop [oldi1]
|
|
63
|
+
push [eax+8*15]
|
|
64
|
+
push [eax+8*15+4]
|
|
65
|
+
pop [oldi15+4]
|
|
66
|
+
pop [oldi15]
|
|
67
|
+
|
|
68
|
+
mov ecx, i1hook
|
|
69
|
+
mov [eax+8*1], ecx
|
|
70
|
+
mov [eax+8*1+4], ecx
|
|
71
|
+
mov ecx, cs
|
|
72
|
+
mov [eax+8*1+2], cx
|
|
73
|
+
mov word ptr [eax+8*1+4], (15 + (3<<5) + (1<<7)) << 8 // call gate
|
|
74
|
+
|
|
75
|
+
mov ecx, i15hook
|
|
76
|
+
mov [eax+8*15], ecx
|
|
77
|
+
mov [eax+8*15+4], ecx
|
|
78
|
+
mov ecx, cs
|
|
79
|
+
mov [eax+8*15+2], cx
|
|
80
|
+
mov word ptr [eax+8*15+4], (15 + (3<<5) + (1<<7)) << 8 // call gate
|
|
81
|
+
ret
|
|
82
|
+
|
|
83
|
+
get_idt:
|
|
84
|
+
sub esp, 8
|
|
85
|
+
sidt [esp]
|
|
86
|
+
mov eax, [esp+2]
|
|
87
|
+
add esp, 8
|
|
88
|
+
ret
|
|
89
|
+
|
|
90
|
+
i1hook:
|
|
91
|
+
push eax
|
|
92
|
+
mov eax, buf
|
|
93
|
+
cmp [eax], bufsz
|
|
94
|
+
jae 1f
|
|
95
|
+
inc [eax]
|
|
96
|
+
add eax, [eax]
|
|
97
|
+
push [esp+4]
|
|
98
|
+
pop [eax]
|
|
99
|
+
1:
|
|
100
|
+
pop eax
|
|
101
|
+
iret
|
|
102
|
+
|
|
103
|
+
i15hook:
|
|
104
|
+
push esi
|
|
105
|
+
push edi
|
|
106
|
+
push ecx
|
|
107
|
+
mov esi, buf
|
|
108
|
+
mov edi, eax
|
|
109
|
+
mov ecx, [esi]
|
|
110
|
+
inc ecx
|
|
111
|
+
rep movsd
|
|
112
|
+
mov dword ptr [buf], 0
|
|
113
|
+
pop ecx
|
|
114
|
+
pop edi
|
|
115
|
+
pop esi
|
|
116
|
+
iret
|
|
117
|
+
EOS
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
DynLdr.new_api_c <<EOS
|
|
121
|
+
typedef int BOOL;
|
|
122
|
+
typedef char CHAR;
|
|
123
|
+
typedef unsigned long DWORD;
|
|
124
|
+
typedef const CHAR *LPCSTR;
|
|
125
|
+
typedef DWORD *LPDWORD;
|
|
126
|
+
typedef void *HANDLE;
|
|
127
|
+
struct SC_HANDLE__ { int unused; };
|
|
128
|
+
struct _SERVICE_STATUS {
|
|
129
|
+
DWORD dwServiceType;
|
|
130
|
+
DWORD dwCurrentState;
|
|
131
|
+
DWORD dwControlsAccepted;
|
|
132
|
+
DWORD dwWin32ExitCode;
|
|
133
|
+
DWORD dwServiceSpecificExitCode;
|
|
134
|
+
DWORD dwCheckPoint;
|
|
135
|
+
DWORD dwWaitHint;
|
|
136
|
+
};
|
|
137
|
+
typedef struct SC_HANDLE__ *SC_HANDLE;
|
|
138
|
+
typedef struct _SERVICE_STATUS *LPSERVICE_STATUS;
|
|
139
|
+
|
|
140
|
+
__stdcall BOOL CloseServiceHandle(SC_HANDLE hSCObject __attribute__((in)));
|
|
141
|
+
__stdcall SC_HANDLE CreateServiceA(SC_HANDLE hSCManager __attribute__((in)), LPCSTR lpServiceName __attribute__((in)), LPCSTR lpDisplayName __attribute__((in)), DWORD dwDesiredAccess __attribute__((in)), DWORD dwServiceType __attribute__((in)), DWORD dwStartType __attribute__((in)), DWORD dwErrorControl __attribute__((in)), LPCSTR lpBinaryPathName __attribute__((in)), LPCSTR lpLoadOrderGroup __attribute__((in)), LPDWORD lpdwTagId __attribute__((out)), LPCSTR lpDependencies __attribute__((in)), LPCSTR lpServiceStartName __attribute__((in)), LPCSTR lpPassword __attribute__((in)));
|
|
142
|
+
__stdcall BOOL DeleteService(SC_HANDLE hService __attribute__((in)));
|
|
143
|
+
__stdcall SC_HANDLE OpenSCManagerA(LPCSTR lpMachineName __attribute__((in)), LPCSTR lpDatabaseName __attribute__((in)), DWORD dwDesiredAccess __attribute__((in)));
|
|
144
|
+
__stdcall SC_HANDLE OpenServiceA(SC_HANDLE hSCManager __attribute__((in)), LPCSTR lpServiceName __attribute__((in)), DWORD dwDesiredAccess __attribute__((in)));
|
|
145
|
+
__stdcall BOOL StartServiceA(SC_HANDLE hService __attribute__((in)), DWORD dwNumServiceArgs __attribute__((in)), LPCSTR *lpServiceArgVectors __attribute__((in)));
|
|
146
|
+
__stdcall BOOL ControlService(SC_HANDLE hService __attribute__((in)), DWORD dwControl __attribute__((in)), LPSERVICE_STATUS lpServiceStatus __attribute__((out)));
|
|
147
|
+
|
|
148
|
+
__stdcall HANDLE OpenThread(DWORD dwDesiredAccess __attribute__((in)), BOOL bInheritHandle __attribute__((in)), DWORD dwThreadId __attribute__((in)));
|
|
149
|
+
__stdcall DWORD ResumeThread(HANDLE hThread __attribute__((in)));
|
|
150
|
+
__stdcall DWORD SuspendThread(HANDLE hThread __attribute__((in)));
|
|
151
|
+
__stdcall BOOL SetThreadContext(HANDLE hThread __attribute__((in)), void *lpContext __attribute__((in)));
|
|
152
|
+
__stdcall BOOL GetThreadContext(HANDLE hThread __attribute__((in)), void *lpContext);
|
|
153
|
+
__stdcall BOOL CloseHandle(HANDLE hObject __attribute__((in)));
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
#define STANDARD_RIGHTS_REQUIRED (0x000F0000L)
|
|
158
|
+
|
|
159
|
+
#define SC_MANAGER_CONNECT 0x0001
|
|
160
|
+
#define SC_MANAGER_CREATE_SERVICE 0x0002
|
|
161
|
+
#define SC_MANAGER_ENUMERATE_SERVICE 0x0004
|
|
162
|
+
#define SC_MANAGER_LOCK 0x0008
|
|
163
|
+
#define SC_MANAGER_QUERY_LOCK_STATUS 0x0010
|
|
164
|
+
#define SC_MANAGER_MODIFY_BOOT_CONFIG 0x0020
|
|
165
|
+
#define SC_MANAGER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \
|
|
166
|
+
SC_MANAGER_CONNECT | \
|
|
167
|
+
SC_MANAGER_CREATE_SERVICE | \
|
|
168
|
+
SC_MANAGER_ENUMERATE_SERVICE | \
|
|
169
|
+
SC_MANAGER_LOCK | \
|
|
170
|
+
SC_MANAGER_QUERY_LOCK_STATUS | \
|
|
171
|
+
SC_MANAGER_MODIFY_BOOT_CONFIG)
|
|
172
|
+
|
|
173
|
+
#define SERVICE_QUERY_CONFIG 0x0001
|
|
174
|
+
#define SERVICE_CHANGE_CONFIG 0x0002
|
|
175
|
+
#define SERVICE_QUERY_STATUS 0x0004
|
|
176
|
+
#define SERVICE_ENUMERATE_DEPENDENTS 0x0008
|
|
177
|
+
#define SERVICE_START 0x0010
|
|
178
|
+
#define SERVICE_STOP 0x0020
|
|
179
|
+
#define SERVICE_PAUSE_CONTINUE 0x0040
|
|
180
|
+
#define SERVICE_INTERROGATE 0x0080
|
|
181
|
+
#define SERVICE_USER_DEFINED_CONTROL 0x0100
|
|
182
|
+
#define SERVICE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \
|
|
183
|
+
SERVICE_QUERY_CONFIG | \
|
|
184
|
+
SERVICE_CHANGE_CONFIG | \
|
|
185
|
+
SERVICE_QUERY_STATUS | \
|
|
186
|
+
SERVICE_ENUMERATE_DEPENDENTS | \
|
|
187
|
+
SERVICE_START | \
|
|
188
|
+
SERVICE_STOP | \
|
|
189
|
+
SERVICE_PAUSE_CONTINUE | \
|
|
190
|
+
SERVICE_INTERROGATE | \
|
|
191
|
+
SERVICE_USER_DEFINED_CONTROL)
|
|
192
|
+
|
|
193
|
+
#define SERVICE_KERNEL_DRIVER 0x00000001
|
|
194
|
+
#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002
|
|
195
|
+
#define SERVICE_ADAPTER 0x00000004
|
|
196
|
+
#define SERVICE_RECOGNIZER_DRIVER 0x00000008
|
|
197
|
+
#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | \
|
|
198
|
+
SERVICE_FILE_SYSTEM_DRIVER | \
|
|
199
|
+
SERVICE_RECOGNIZER_DRIVER)
|
|
200
|
+
#define SERVICE_WIN32_OWN_PROCESS 0x00000010
|
|
201
|
+
#define SERVICE_WIN32_SHARE_PROCESS 0x00000020
|
|
202
|
+
#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | \
|
|
203
|
+
SERVICE_WIN32_SHARE_PROCESS)
|
|
204
|
+
#define SERVICE_INTERACTIVE_PROCESS 0x00000100
|
|
205
|
+
#define SERVICE_TYPE_ALL (SERVICE_WIN32 | \
|
|
206
|
+
SERVICE_ADAPTER | \
|
|
207
|
+
SERVICE_DRIVER | \
|
|
208
|
+
SERVICE_INTERACTIVE_PROCESS)
|
|
209
|
+
|
|
210
|
+
#define SERVICE_BOOT_START 0x00000000
|
|
211
|
+
#define SERVICE_SYSTEM_START 0x00000001
|
|
212
|
+
#define SERVICE_AUTO_START 0x00000002
|
|
213
|
+
#define SERVICE_DEMAND_START 0x00000003
|
|
214
|
+
#define SERVICE_DISABLED 0x00000004
|
|
215
|
+
|
|
216
|
+
#define SERVICE_ERROR_IGNORE 0x00000000
|
|
217
|
+
#define SERVICE_ERROR_NORMAL 0x00000001
|
|
218
|
+
#define SERVICE_ERROR_SEVERE 0x00000002
|
|
219
|
+
#define SERVICE_ERROR_CRITICAL 0x00000003
|
|
220
|
+
|
|
221
|
+
#define SYNCHRONIZE 0x00100000L
|
|
222
|
+
#define THREAD_TERMINATE 0x0001
|
|
223
|
+
#define THREAD_SUSPEND_RESUME 0x0002
|
|
224
|
+
#define THREAD_GET_CONTEXT 0x0008
|
|
225
|
+
#define THREAD_SET_CONTEXT 0x0010
|
|
226
|
+
#define THREAD_SET_INFORMATION 0x0020
|
|
227
|
+
#define THREAD_QUERY_INFORMATION 0x0040
|
|
228
|
+
#define THREAD_SET_THREAD_TOKEN 0x0080
|
|
229
|
+
#define THREAD_IMPERSONATE 0x0100
|
|
230
|
+
#define THREAD_DIRECT_IMPERSONATION 0x0200
|
|
231
|
+
#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF)
|
|
232
|
+
|
|
233
|
+
#define CONTEXT_i386 0x00010000
|
|
234
|
+
#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
|
|
235
|
+
EOS
|
|
236
|
+
|
|
237
|
+
DynLdr.new_func_c <<EOS
|
|
238
|
+
int get_trace_buf(void *ptr)
|
|
239
|
+
{
|
|
240
|
+
asm("mov eax, [ebp+8] int 0fh");
|
|
241
|
+
return *(int*)ptr;
|
|
242
|
+
}
|
|
243
|
+
EOS
|
|
244
|
+
|
|
245
|
+
def loadmod(mod=$drv)
|
|
246
|
+
sh = DynLdr.openscmanagera(0, 0, DynLdr::SC_MANAGER_ALL_ACCESS)
|
|
247
|
+
raise "cannot openscm" if (sh == 0)
|
|
248
|
+
rh = DynLdr.createservicea(sh, mod, mod, DynLdr::SERVICE_ALL_ACCESS, DynLdr::SERVICE_KERNEL_DRIVER, DynLdr::SERVICE_DEMAND_START, DynLdr::SERVICE_ERROR_NORMAL, File.expand_path(mod), 0, 0, 0, 0, 0)
|
|
249
|
+
if (DynLdr.startservicea(rh, 0, 0) == 0)
|
|
250
|
+
raise "cannot start service"
|
|
251
|
+
end
|
|
252
|
+
DynLdr.CloseServiceHandle(rh)
|
|
253
|
+
DynLdr.CloseServiceHandle(sh)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def unloadmod(mod=$drv)
|
|
257
|
+
sh = DynLdr.openscmanagera(0, 0, DynLdr::SC_MANAGER_ALL_ACCESS)
|
|
258
|
+
raise "cannot openscm" if (sh == 0)
|
|
259
|
+
rh = DynLdr.openservicea(sh, mod, DynLdr::SERVICE_ALL_ACCESS)
|
|
260
|
+
DynLdr.controlservice(rh, DynLdr::SERVICE_CONTROL_STOP, 0.chr*4*32)
|
|
261
|
+
DynLdr.deleteservice(rh)
|
|
262
|
+
DynLdr.CloseServiceHandle(rh)
|
|
263
|
+
DynLdr.CloseServiceHandle(sh)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def trace(tid, delay=1)
|
|
267
|
+
# put thread in singlestep mode
|
|
268
|
+
th = DynLdr.openthread(DynLdr::THREAD_GET_CONTEXT | DynLdr::THREAD_SET_CONTEXT | DynLdr::THREAD_SUSPEND_RESUME, 0, tid)
|
|
269
|
+
raise "openthread" if (th == 0)
|
|
270
|
+
DynLdr.suspendthread(th)
|
|
271
|
+
ctx = 0.chr * 1024
|
|
272
|
+
ctx[0, 4] = [DynLdr::CONTEXT_CONTROL].pack('V')
|
|
273
|
+
DynLdr.getthreadcontext(th, ctx)
|
|
274
|
+
ctx[192, 4] = [ctx[192, 4].unpack('V').first | (1 << 8)].pack('V')
|
|
275
|
+
DynLdr.setthreadcontext(th, ctx)
|
|
276
|
+
DynLdr.resumethread(th)
|
|
277
|
+
DynLdr.closehandle(th)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
buf = 0.chr * 4 * TRACE_BUF_SZ
|
|
281
|
+
loop do
|
|
282
|
+
sleep delay.to_f
|
|
283
|
+
nr = DynLdr.get_trace_buf(buf)
|
|
284
|
+
puts "got #{'%x' % nr} instrs"
|
|
285
|
+
# eips = buf[4, 4*nr].unpack('V*')
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
ensure
|
|
289
|
+
th = DynLdr.openthread(DynLdr::THREAD_GET_CONTEXT | DynLdr::THREAD_SET_CONTEXT | DynLdr::THREAD_SUSPEND_RESUME, 0, tid)
|
|
290
|
+
if (th != 0)
|
|
291
|
+
DynLdr.suspendthread(th)
|
|
292
|
+
ctx = 0.chr * 1024
|
|
293
|
+
ctx[0, 4] = [DynLdr::CONTEXT_CONTROL].pack('V')
|
|
294
|
+
DynLdr.getthreadcontext(th, ctx)
|
|
295
|
+
ctx[192, 4] = [ctx[192, 4].unpack('V').first & ~(1 << 8)].pack('V')
|
|
296
|
+
DynLdr.setthreadcontext(th, ctx)
|
|
297
|
+
DynLdr.resumethread(th)
|
|
298
|
+
DynLdr.closehandle(th)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
if $0 == __FILE__
|
|
303
|
+
case ARGV.shift
|
|
304
|
+
when /unload/; unloadmod(*ARGV)
|
|
305
|
+
when /load/; loadmod(*ARGV)
|
|
306
|
+
when /trace/; trace(*ARGV)
|
|
307
|
+
end
|
|
308
|
+
end
|
data/samples/rubstop.rb
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
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
|
+
#
|
|
7
|
+
# this exemple illustrates the use of the PTrace class to implement a pytstop-like functionnality
|
|
8
|
+
# Works on linux/x86
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require 'metasm'
|
|
12
|
+
|
|
13
|
+
class Rubstop < Metasm::PTrace
|
|
14
|
+
EFLAGS = {0 => 'c', 2 => 'p', 4 => 'a', 6 => 'z', 7 => 's', 9 => 'i', 10 => 'd', 11 => 'o'}
|
|
15
|
+
# define accessors for registers
|
|
16
|
+
%w[eax ebx ecx edx ebp esp edi esi eip orig_eax eflags dr0 dr1 dr2 dr3 dr6 dr7 cs ds es fs gs].each { |reg|
|
|
17
|
+
define_method(reg) { peekusr(REGS_I386[reg.upcase]) & 0xffffffff }
|
|
18
|
+
define_method(reg+'=') { |v|
|
|
19
|
+
@regs_cache[reg] = v
|
|
20
|
+
v = [v & 0xffffffff].pack('L').unpack('l').first if v >= 0x8000_0000
|
|
21
|
+
pokeusr(REGS_I386[reg.upcase], v)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
def cont(signal=0)
|
|
26
|
+
@ssdontstopbp = nil
|
|
27
|
+
singlestep(true) if @wantbp
|
|
28
|
+
super(signal)
|
|
29
|
+
::Process.waitpid(@pid)
|
|
30
|
+
return if child.exited?
|
|
31
|
+
@oldregs.update @regs_cache
|
|
32
|
+
readregs
|
|
33
|
+
checkbp
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def singlestep(justcheck=false)
|
|
37
|
+
super()
|
|
38
|
+
::Process.waitpid(@pid)
|
|
39
|
+
return if child.exited?
|
|
40
|
+
case @wantbp
|
|
41
|
+
when ::Integer; bpx @wantbp ; @wantbp = nil
|
|
42
|
+
when ::String; self.dr7 |= 1 << (2*@wantbp[2, 1].to_i) ; @wantbp = nil
|
|
43
|
+
end
|
|
44
|
+
return if justcheck
|
|
45
|
+
@oldregs.update @regs_cache
|
|
46
|
+
readregs
|
|
47
|
+
checkbp
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def stepover
|
|
51
|
+
i = curinstr.instruction if curinstr
|
|
52
|
+
if i and (i.opname == 'call' or (i.prefix and i.prefix[:rep]))
|
|
53
|
+
eaddr = @regs_cache['eip'] + curinstr.bin_length
|
|
54
|
+
bpx eaddr, true
|
|
55
|
+
cont
|
|
56
|
+
else
|
|
57
|
+
singlestep
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def stepout
|
|
62
|
+
# XXX @regs_cache..
|
|
63
|
+
stepover until curinstr.opcode.name == 'ret'
|
|
64
|
+
singlestep
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def syscall
|
|
68
|
+
@ssdontstopbp = nil
|
|
69
|
+
singlestep(true) if @wantbp
|
|
70
|
+
super()
|
|
71
|
+
::Process.waitpid(@pid)
|
|
72
|
+
return if child.exited?
|
|
73
|
+
@oldregs.update @regs_cache
|
|
74
|
+
readregs
|
|
75
|
+
checkbp
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def state; :stopped end
|
|
79
|
+
def ptrace; self end
|
|
80
|
+
|
|
81
|
+
attr_accessor :pgm, :regs_cache, :breakpoints, :singleshot, :wantbp,
|
|
82
|
+
:symbols, :symbols_len, :filemap, :has_pax, :oldregs
|
|
83
|
+
def initialize(*a)
|
|
84
|
+
super(*a)
|
|
85
|
+
@pgm = Metasm::ExeFormat.new Metasm::Ia32.new
|
|
86
|
+
@pgm.encoded = Metasm::EncodedData.new Metasm::LinuxRemoteString.new(@pid)
|
|
87
|
+
@pgm.encoded.data.dbg = self
|
|
88
|
+
@regs_cache = {}
|
|
89
|
+
@oldregs = {}
|
|
90
|
+
readregs
|
|
91
|
+
@oldregs.update @regs_cache
|
|
92
|
+
@breakpoints = {}
|
|
93
|
+
@singleshot = {}
|
|
94
|
+
@wantbp = nil
|
|
95
|
+
@symbols = {}
|
|
96
|
+
@symbols_len = {}
|
|
97
|
+
@filemap = {}
|
|
98
|
+
@has_pax = false
|
|
99
|
+
|
|
100
|
+
stack = self[regs_cache['esp'], 0x1000].to_str.unpack('L*')
|
|
101
|
+
stack.shift # argc
|
|
102
|
+
stack.shift until stack.empty? or stack.first == 0 # argv
|
|
103
|
+
stack.shift
|
|
104
|
+
stack.shift until stack.empty? or stack.first == 0 # envp
|
|
105
|
+
stack.shift
|
|
106
|
+
stack.shift until stack.empty? or stack.shift == 3 # find PHDR ptr in auxv
|
|
107
|
+
if phdr = stack.shift
|
|
108
|
+
phdr &= 0xffff_f000
|
|
109
|
+
loadsyms phdr, phdr.to_s(16)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def set_pax(bool)
|
|
114
|
+
if bool
|
|
115
|
+
@pgm.encoded.data.invalidate
|
|
116
|
+
code = @pgm.encoded.data[eip, 4]
|
|
117
|
+
if code != "\0\0\0\0" and @pgm.encoded.data[eip+0x6000_0000, 4] == code
|
|
118
|
+
@has_pax = 'segmexec'
|
|
119
|
+
else
|
|
120
|
+
@has_pax = 'pax'
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
@has_pax = false
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def readregs
|
|
128
|
+
%w[eax ebx ecx edx esi edi esp ebp eip orig_eax eflags dr0 dr1 dr2 dr3 dr6 dr7 cs ds].each { |r| @regs_cache[r] = send(r) }
|
|
129
|
+
@curinstr = nil if @regs_cache['eip'] != @oldregs['eip']
|
|
130
|
+
@pgm.encoded.data.invalidate
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def curinstr
|
|
134
|
+
@curinstr ||= mnemonic_di
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def child
|
|
138
|
+
$?
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def checkbp
|
|
142
|
+
::Process::waitpid(@pid, ::Process::WNOHANG) if not child
|
|
143
|
+
return if not child
|
|
144
|
+
if not child.stopped?
|
|
145
|
+
if child.exited?; log "process exited with status #{child.exitstatus}"
|
|
146
|
+
elsif child.signaled?; log "process exited due to signal #{child.termsig} (#{Signal.list.index child.termsig})"
|
|
147
|
+
else log "process in unknown status #{child.inspect}"
|
|
148
|
+
end
|
|
149
|
+
return
|
|
150
|
+
elsif child.stopsig != ::Signal.list['TRAP']
|
|
151
|
+
log "process stopped due to signal #{child.stopsig} (#{Signal.list.index child.stopsig})"
|
|
152
|
+
return # do not check 0xcc at eip-1 ! ( if curinstr.bin_length == 1 )
|
|
153
|
+
end
|
|
154
|
+
ccaddr = @regs_cache['eip']-1
|
|
155
|
+
if @breakpoints[ccaddr] and self[ccaddr] == 0xcc
|
|
156
|
+
if @ssdontstopbp != ccaddr
|
|
157
|
+
self[ccaddr] = @breakpoints.delete ccaddr
|
|
158
|
+
self.eip = ccaddr
|
|
159
|
+
@wantbp = ccaddr if not @singleshot.delete ccaddr
|
|
160
|
+
@ssdontstopbp = ccaddr
|
|
161
|
+
else
|
|
162
|
+
@ssdontstopbp = nil
|
|
163
|
+
end
|
|
164
|
+
elsif @regs_cache['dr6'] & 15 != 0
|
|
165
|
+
dr = (0..3).find { |dr_| @regs_cache['dr6'] & (1 << dr_) != 0 }
|
|
166
|
+
@wantbp = "dr#{dr}" if not @singleshot.delete @regs_cache['eip']
|
|
167
|
+
self.dr6 = 0
|
|
168
|
+
self.dr7 = @regs_cache['dr7'] & (0xffff_ffff ^ (3 << (2*dr)))
|
|
169
|
+
readregs
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def bpx(addr, singleshot=false)
|
|
174
|
+
@singleshot[addr] = singleshot
|
|
175
|
+
return if @breakpoints[addr]
|
|
176
|
+
if @has_pax
|
|
177
|
+
set_hwbp 'x', addr
|
|
178
|
+
else
|
|
179
|
+
begin
|
|
180
|
+
@breakpoints[addr] = self[addr]
|
|
181
|
+
self[addr] = 0xcc
|
|
182
|
+
rescue Errno::EIO
|
|
183
|
+
log 'i/o error when setting breakpoint, switching to PaX mode'
|
|
184
|
+
set_pax true
|
|
185
|
+
@breakpoints.delete addr
|
|
186
|
+
bpx(addr, singleshot)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def mnemonic_di(addr = eip)
|
|
192
|
+
@pgm.encoded.ptr = addr
|
|
193
|
+
di = @pgm.cpu.decode_instruction(@pgm.encoded, addr)
|
|
194
|
+
@curinstr = di if addr == @regs_cache['eip']
|
|
195
|
+
di
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def mnemonic(addr=eip)
|
|
199
|
+
mnemonic_di(addr).instruction
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def regs_dump
|
|
203
|
+
[%w[eax ebx ecx edx orig_eax], %w[ebp esp edi esi eip]].map { |l|
|
|
204
|
+
l.map { |reg| "#{reg}=#{'%08x' % @regs_cache[reg]}" }.join(' ')
|
|
205
|
+
}.join("\n")
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def findfilemap(s)
|
|
209
|
+
@filemap.keys.find { |k| @filemap[k][0] <= s and @filemap[k][1] > s } || '???'
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def findsymbol(k)
|
|
213
|
+
file = findfilemap(k) + '!'
|
|
214
|
+
if s = @symbols[k] ? k : @symbols.keys.find { |s_| s_ < k and s_ + @symbols_len[s_].to_i > k }
|
|
215
|
+
file + @symbols[s] + (s == k ? '' : "+#{(k-s).to_s(16)}")
|
|
216
|
+
else
|
|
217
|
+
file + ('%08x' % k)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def set_hwbp(type, addr, len=1)
|
|
222
|
+
dr = (0..3).find { |dr_| @regs_cache['dr7'] & (1 << (2*dr_)) == 0 and @wantbp != "dr#{dr}" }
|
|
223
|
+
if not dr
|
|
224
|
+
log 'no debug reg available :('
|
|
225
|
+
return false
|
|
226
|
+
end
|
|
227
|
+
@regs_cache['dr7'] &= 0xffff_ffff ^ (0xf << (16+4*dr))
|
|
228
|
+
case type
|
|
229
|
+
when 'x'; addr += (@has_pax == 'segmexec' ? 0x6000_0000 : 0)
|
|
230
|
+
when 'r'; @regs_cache['dr7'] |= (((len-1)<<2)|3) << (16+4*dr)
|
|
231
|
+
when 'w'; @regs_cache['dr7'] |= (((len-1)<<2)|1) << (16+4*dr)
|
|
232
|
+
end
|
|
233
|
+
send("dr#{dr}=", addr)
|
|
234
|
+
self.dr6 = 0
|
|
235
|
+
self.dr7 = @regs_cache['dr7'] | (1 << (2*dr))
|
|
236
|
+
readregs
|
|
237
|
+
true
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def clearbreaks
|
|
241
|
+
@wantbp = nil if @wantbp == @regs_cache['eip']
|
|
242
|
+
@breakpoints.each { |addr, oct| self[addr, 1] = oct }
|
|
243
|
+
@breakpoints.clear
|
|
244
|
+
if @regs_cache['dr7'] & 0xff != 0
|
|
245
|
+
self.dr7 = 0
|
|
246
|
+
readregs
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def loadsyms(baseaddr, name)
|
|
251
|
+
@loadedsyms ||= {}
|
|
252
|
+
return if @loadedsyms[name] or self[baseaddr, 4] != "\x7fELF"
|
|
253
|
+
@loadedsyms[name] = true
|
|
254
|
+
|
|
255
|
+
set_status " loading symbols from #{name}..."
|
|
256
|
+
e = Metasm::LoadedELF.load self[baseaddr, 0x100_0000]
|
|
257
|
+
e.load_address = baseaddr
|
|
258
|
+
begin
|
|
259
|
+
e.decode
|
|
260
|
+
#e = Metasm::ELF.decode_file name rescue return # read from disk
|
|
261
|
+
rescue
|
|
262
|
+
log "failed to load symbols from #{name}: #$!"
|
|
263
|
+
($!.backtrace - caller).each { |l| log l.chomp }
|
|
264
|
+
@filemap[baseaddr.to_s(16)] = [baseaddr, baseaddr+0x1000]
|
|
265
|
+
return
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
if e.tag['SONAME']
|
|
269
|
+
name = e.tag['SONAME']
|
|
270
|
+
return if name and @loadedsyms[name]
|
|
271
|
+
@loadedsyms[name] = true
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
last_s = e.segments.reverse.find { |s| s.type == 'LOAD' }
|
|
275
|
+
vlen = last_s.vaddr + last_s.memsz
|
|
276
|
+
vlen -= baseaddr if e.header.type == 'EXEC'
|
|
277
|
+
@filemap[name] = [baseaddr, baseaddr + vlen]
|
|
278
|
+
|
|
279
|
+
oldsyms = @symbols.length
|
|
280
|
+
e.symbols.each { |s|
|
|
281
|
+
next if not s.name or s.shndx == 'UNDEF'
|
|
282
|
+
sname = s.name
|
|
283
|
+
sname = 'weak_'+sname if s.bind == 'WEAK'
|
|
284
|
+
sname = 'local_'+sname if s.bind == 'LOCAL'
|
|
285
|
+
v = s.value
|
|
286
|
+
v = baseaddr + v if v < baseaddr
|
|
287
|
+
@symbols[v] = sname
|
|
288
|
+
@symbols_len[v] = s.size
|
|
289
|
+
}
|
|
290
|
+
if e.header.type == 'EXEC'
|
|
291
|
+
@symbols[e.header.entry] = 'entrypoint'
|
|
292
|
+
end
|
|
293
|
+
set_status nil
|
|
294
|
+
log "loaded #{@symbols.length-oldsyms} symbols from #{name} at #{'%08x' % baseaddr}"
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def loadallsyms
|
|
298
|
+
File.read("/proc/#{@pid}/maps").each { |l|
|
|
299
|
+
name = l.split[5]
|
|
300
|
+
loadsyms l.to_i(16), name if name and name[0] == ?/
|
|
301
|
+
}
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def loadmap(mapfile)
|
|
305
|
+
# file fmt: addr type name eg 'c01001ba t setup_idt'
|
|
306
|
+
minaddr = maxaddr = nil
|
|
307
|
+
File.read(mapfile).each { |l|
|
|
308
|
+
addr, type, name = l.chomp.split
|
|
309
|
+
addr = addr.to_i(16)
|
|
310
|
+
minaddr = addr if not minaddr or minaddr > addr
|
|
311
|
+
maxaddr = addr if not maxaddr or maxaddr < addr
|
|
312
|
+
@symbols[addr] = name
|
|
313
|
+
}
|
|
314
|
+
if minaddr
|
|
315
|
+
@filemap[minaddr.to_s(16)] = [minaddr, maxaddr+1]
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def scansyms
|
|
320
|
+
addr = 0
|
|
321
|
+
fd = @pgm.encoded.data.readfd
|
|
322
|
+
while addr <= 0xffff_f000
|
|
323
|
+
addr = 0xc000_0000 if @has_pax and addr == 0x6000_0000
|
|
324
|
+
log "scansym: #{'%08x' % addr}" if addr & 0x0fff_ffff == 0
|
|
325
|
+
fd.pos = addr
|
|
326
|
+
loadsyms(addr, '%08x'%addr) if (fd.read(4) == "\x7fELF" rescue false)
|
|
327
|
+
addr += 0x1000
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def backtrace
|
|
332
|
+
s = findsymbol(@regs_cache['eip'])
|
|
333
|
+
if block_given?
|
|
334
|
+
yield s
|
|
335
|
+
else
|
|
336
|
+
bt = []
|
|
337
|
+
bt << s
|
|
338
|
+
end
|
|
339
|
+
fp = @regs_cache['ebp']
|
|
340
|
+
while fp >= @regs_cache['esp'] and fp <= @regs_cache['esp']+0x10000
|
|
341
|
+
s = findsymbol(self[fp+4, 4].unpack('L').first)
|
|
342
|
+
if block_given?
|
|
343
|
+
yield s
|
|
344
|
+
else
|
|
345
|
+
bt << s
|
|
346
|
+
end
|
|
347
|
+
fp = self[fp, 4].unpack('L').first
|
|
348
|
+
end
|
|
349
|
+
bt
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def [](addr, len=nil)
|
|
353
|
+
@pgm.encoded.data[addr, len]
|
|
354
|
+
end
|
|
355
|
+
def []=(addr, len, str=nil)
|
|
356
|
+
@pgm.encoded.data[addr, len] = str
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
attr_accessor :logger
|
|
360
|
+
def log(s)
|
|
361
|
+
@logger ||= $stdout
|
|
362
|
+
@logger.puts s
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# set a temporary status info (nil for default value)
|
|
366
|
+
def set_status(s)
|
|
367
|
+
@logger ||= $stdout
|
|
368
|
+
if @logger != $stdout
|
|
369
|
+
@logger.statusline = s
|
|
370
|
+
else
|
|
371
|
+
s ||= ' '*72
|
|
372
|
+
@logger.print s + "\r"
|
|
373
|
+
@logger.flush
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
if $0 == __FILE__
|
|
379
|
+
# start debugging
|
|
380
|
+
rs = Rubstop.new(ARGV.shift)
|
|
381
|
+
|
|
382
|
+
begin
|
|
383
|
+
while rs.child.stopped? and rs.child.stopsig == Signal.list['TRAP']
|
|
384
|
+
if $VERBOSE
|
|
385
|
+
puts "#{'%08x' % rs.eip} #{rs.mnemonic}"
|
|
386
|
+
rs.singlestep
|
|
387
|
+
else
|
|
388
|
+
rs.syscall ; rs.syscall # wait return of syscall
|
|
389
|
+
puts "#{rs.orig_eax.to_s.ljust(3)} #{rs.syscallnr.index rs.orig_eax}"
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
p rs.child
|
|
393
|
+
puts rs.regs_dump
|
|
394
|
+
rescue Interrupt
|
|
395
|
+
rs.detach rescue nil
|
|
396
|
+
puts 'interrupted!'
|
|
397
|
+
rescue Errno::ESRCH
|
|
398
|
+
end
|
|
399
|
+
end
|