def test_retset(): cmdline = (sys.executable + ' -c "import ctypes; ctypes.cdll.dll.Add(1, 1)"') dbg = Qdb() locs = {'marker': None} dbg.add_query('dll.Add', "marker = retset('eax+1', 8)") result = dbg.run(cmdline, locs) assert result is True assert locs['marker'] == 3
def test_db(): dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401010, "marker = db('poi(esp)', 1)") result = False result = dbg.run(hello_exe_path, locs) assert result is True # DWORD of beginning of "Hello, world!" assert locs['marker'][0] == struct.unpack('B', 'H')[0]
def test_bp(): """FIXME: This test will break if da breaks, which is confusing.""" dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401000, "bp(0x401010, 'marker = da(\\\'poi(esp)\\\', 5)')") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] == 'Hello'
def test_da(): dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401010, "marker = da('poi(esp)'); print('Marker = ' + str(marker))") result = dbg.run(hello_exe_path, locs) assert result is True # DWORD of beginning of "Hello, world!" assert locs['marker'] == 'Hello, world!\n\0'
def test_park_detach_attach_unpark(): """This will spike CPU while the debuggee executes jmp -2 a few thousand times. """ dbg = Qdb() locs = {'pid': None, 'flag': None} dbg.add_query(0x401010, "park(); pid = detach()") result = dbg.run(hello_exe_path, locs) assert result is True dbg = Qdb() dbg.attach(locs['pid']) dbg.add_query(0x401021, "flag = -1") dbg.unpark() result = dbg.run(parameters=locs) assert result is True assert locs['flag'] == -1
def test_kill(): dbg = Qdb() locs = {'marker1': None, 'marker2': None} dbg.add_query(0x401010, "marker1 = kill()") dbg.add_query(0x40101b, "marker2 = vex('poi(ebp-0x4)')") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker1'] is True assert locs['marker2'] is None
def test_stepi(): dbg = Qdb() locs = {'location': None} dbg.add_query(0x401010, "stepi(); location = r('eip')") # call _printf result = dbg.run(hello_exe_path, locs) assert result is True assert locs['location'] assert locs['location'] == (0xD + 0x401015) # At _printf
def test_python_ctypes_dll_intercept(): cmdline = (sys.executable + ' -c "import ctypes; ctypes.cdll.dll.Add(40, 2)"') dbg = Qdb() locs = {'marker': None} dbg.add_query('dll.Add+0xd', "marker = r('eax')") result = dbg.run(cmdline, locs) assert result is True assert locs['marker'] == 42
def test_eb2(): sentinel_value = 0xffff dbg = Qdb() locs = {'marker': None} # [ebp-4] here is equal to the length of the string "Hello, world!\n" dbg.add_query(0x40101b, "eb('ebp-4', '\xff\xff')") dbg.add_query(0x40101e, "marker = r('eax')") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] == sentinel_value
def test_eb1(): sentinel_value = 0x0f dbg = Qdb() locs = {'marker': None} # [ebp-4] here is equal to the length of the string "Hello, world!\n" dbg.add_query(0x40101b, "eb('ebp-4', " + str(sentinel_value) + ")") dbg.add_query(0x40101e, "marker = r('eax')") result = dbg.run('hello.exe', locs) assert result is True assert locs['marker'] == sentinel_value
def test_memcpy(): """FIXME: This test will break if dd breaks, which is confusing.""" dbg = Qdb() locs = {'marker': None} dbg.add_query( 0x401010, "memcpy('poi(esp)', 'poi(esp)+4', 4); " + "marker = dd('poi(esp)', 1)") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'][0] == struct.unpack('@I', 'Hello, world!'[4:8])[0]
def test_one_mb_read_limit(): ONE_MB = 1024 * 1024 MORE = ONE_MB + 10 PAGE_READWRITE = 0x4 MEM_COMMIT = 0x1000 MEM_RESERVE = 0x2000 locs = {'location': None, 'size': None} args = ( ' -c "import ctypes; ' 'm = ctypes.windll.kernel32.VirtualAlloc(' + hex(0).rstrip('L') + ', ' + hex(MORE).rstrip('L') + ', ' + hex(MEM_COMMIT | MEM_RESERVE).rstrip('L') + ', ' + hex(PAGE_READWRITE).rstrip('L') + '); ' # Disclose the location of the memory returned by VirtualAlloc 'ctypes.windll.kernel32.VirtualQuery(m, 0, 0);' # Trigger one more breakpoint for clarity 'ctypes.windll.kernel32.VirtualFree(' + 'm, ' + hex(MORE).rstrip('L') + ', ' + '0x8000' + ');') # When running under py.test.exe, sys.executable is python.exe cmdline = sys.executable + args dbg = Qdb() dbg.add_query( 'kernel32.VirtualQuery', # If lpBuffer + dwLength == NULL, then this is the Python # script's indication to qdb of where the memory is located. # Read it. "if not sum(dd('esp+8', 2)): location = dd('esp+4', 1)[0]; ") # VirtualFree is called by the debuggee (above) to trigger this code. dbg.add_query( 'kernel32.VirtualFree', "m = readmem(" "location, " + hex(MORE).rstrip('L') + ", " "1, " "None" ");" "size = len(m)" # Collect the length that was read ) result = dbg.run(cmdline, locs) assert result is True # If we did not get the location, that is useful to know for diagnosing # test failure. assert locs['location'] # Check that ONE_MB of data was returned despite having tried to read MORE assert locs['size'] == ONE_MB
def test_get_pcs(): dbg = Qdb() locs = {'pcs': None, 'tid': None} pc = 0x401000 dbg.add_query(pc, 'pcs = get_pcs(); tid = q._trace.getCurrentThread()') result = dbg.run(hello_exe_path, locs) assert result is True # hello.exe is single-threaded for k, v in locs['pcs'].iteritems(): assert k == locs['tid'] assert v == pc
def test_eu_and_du(): """FIXME: This test depends on both eu and du, which makes it break when either piece breaks. """ dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401010, "eu('poi(esp)', u'Bye, world'); marker = du('poi(esp)', 3)") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] == u'Bye'
def test_ea_and_da(): """FIXME: This test depends on both ea and da, which makes it break when either piece breaks. """ dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401010, "ea('poi(esp)', 'Bye, world'); marker = da('poi(esp)')") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] == 'Bye, worldld!\n\0'
def test_callback_gets_context_with_pc_and_locals_as_arg(*args, **kwargs): dbg = Qdb() def callback(p, **kwargs): p['marker'] = True locs = {'marker': False} dbg.add_query(0x401010, callback) result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] is True
def test_get_push_arg(): cmdline = (sys.executable + ' -c "import ctypes; ctypes.cdll.dll.Add(12, 34)"') dbg = Qdb() locs = {'arg_12': None, 'arg_34': None} dbg.add_query('dll.Add', "arg_12 = get_push_arg(0); arg_34 = get_push_arg(1)") result = dbg.run(cmdline, locs) assert result is True assert locs['arg_12'] == 12 assert locs['arg_34'] == 34
def test_gu(): dbg = Qdb() locs = {'location': None} dbg.add_query( 0x401022, "print(hex(r('eip'))); gu(); location = r('eip'); print(hex(location))" ) # At _printf result = dbg.run(hello_exe_path, locs) assert result is True assert locs['location'] assert locs['location'] == 0x401015 # Right after call _printf
def test_writemem(): """FIXME: This test will break if da breaks, which is confusing.""" dbg = Qdb() locs = {'marker': None} s = "Goodbye, world!" print("writemem('poi(esp)', '" + s + "'); marker = da('poi(esp)')") dbg.add_query( 0x401010, "writemem('poi(esp)', '" + s + "\\x00'); marker = da('poi(esp)')") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] == s + '\x00'
def test_rapid_fire_WILL_TAKE_A_LONG_TIME(): runs_expected = 1 # runs_expected = 1400 runs_counted = 0 locs = {'marker': runs_counted} dbg = Qdb() dbg.add_query(0x0401262, "marker += 1; kill()") for i in xrange(runs_expected): result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'] == runs_expected
def test_vexpr_nameerror(): dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401010, "marker = vex('poi(EXP)')") got_exception = False try: result = dbg.run(hello_exe_path, locs) except QdbBpException as e: got_exception = True ex_type_is_name_error = isinstance(e.exception, NameError) assert got_exception assert ex_type_is_name_error assert locs['marker'] is None
def test_disas_alias_uf(): dbg = Qdb() locs = {'marker': None} dbg.add_query(0x401000, "marker = uf(None)") result = dbg.run(hello_exe_path, locs) assert result is True assert locs['marker'][0].startswith('push ebp') assert locs['marker'][1].startswith('mov ebp,esp') assert locs['marker'][2].startswith('push ecx') assert locs['marker'][3].startswith('mov dword [ebp - 4],0') assert locs['marker'][4].startswith('push 0x0040c000') assert locs['marker'][5].startswith('call 0x00401022') assert locs['marker'][6].startswith('add esp,4') assert locs['marker'][7].startswith('mov dword [ebp - 4],eax') assert locs['marker'][8].startswith('mov eax,dword [ebp - 4]') assert locs['marker'][9].startswith('mov esp,ebp') assert locs['marker'][10].startswith('pop ebp') assert locs['marker'][11].startswith('ret')
def _test_stacktrace(command="stacktrace()"): dbg = Qdb() locs = {'backtrace': None} dbg.add_query(0x401022, 'backtrace = %s' % (command)) result = dbg.run(hello_exe_path, locs) assert result is True assert locs['backtrace'] bt = locs['backtrace'] # At least main, _printf, and one other frame assert len(bt) > 2 # Stack frames numbered as expected assert all([(bt[i].nr == i) for i in range(len(bt))]) # ebp direction as expected assert all([(bt[i].bp < bt[i + 1].bp) for i in range(len(bt) - 1)]) # Known addresses that should be at the top of this stack frame assert bt[0].pc == 0x401022 assert bt[0].pc_s == 'hello+0x22' assert bt[1].pc == 0x40120b assert bt[1].pc_s == 'hello+0x20b'
def test_run_no_breaks_and_exitcode(): dbg = Qdb() result = dbg.run(hello_exe_path) assert result is True assert dbg.get_exitcode() == 14
def test_python_ctypes_dll_control_case(): cmdline = (sys.executable + ' -c "import ctypes; ctypes.windll.dll.Add(1, 2)"') dbg = Qdb() result = dbg.run(cmdline) assert result is True
def test_rundll_dll_control_case(): dbg = Qdb() result = dbg.run(r'rundll32.exe dll.dll,Add') assert result is True