Numbers are in hexadecimal format by default (if not defined differently in the help file - as e.g. floating point numbers which are not in hexadecimal form of course).
Please report bugs and disassembler mistakes to me, possible ways are:
if you are looking for fdbg for Linux x64, try these links:
the syntax is:
fdbg.exe -d -n -t debuggee.exe params_for_debuggee
-d reset arrangement (positions, sizes, saved settings) to the default
-n stop the debuggee in initial int3 (earlier than at the debuggee entry point - OEP - entry point is shown in the Log window as 'ThreadStartAddress=' in the line beginnig with 'Process created.'), this is the same as unchecking the checkbox 'run over initial int3 and halt on exe entry point' in the open debuggee menu and is usually unwanted unless you do some advanced debugging
-t forces to debug only this process (prevents its children from being debugged), this is the same as checking the checkbox 'debug only this process (exclude children)' in the open debuggee menu
debuggee.exe the name of program being debugged
params_for_debuggee parameters passed to program being debugged, may be more strings separated by space including other switches
imagine this sample:
fdbg.exe -d -t notepad.exe -n project1.asm text2.txt
note that in the above sample, the -n param is passed into debuggee (notepad.exe), not for fdbg, there are only -d -t params passed for fdbg, the notepad.exe program (debuggee) is run with 3 parameters:
-n
project1.asm
text2.txt
DEBUG_ONLY_THIS_PROCESS
, leave checkbox unchecked if you want to be notified about child process debug eventsany explanation isn't necessary.
terminate debuggee and then resurrect it again (the same like: 1. terminate, 2. open debuggee with the same parameters).
shows you a list of processes which you can doubleclick from. You can attach only 64-bit processes. If fdbg shows ??-bit for any process then it is usualy unable to attach to this process.
DebugSetProcessKillOnExit: If checked, the debug thread will kill the process being debugged on exit. Otherwise, the debug thread will detach from the process being debugged on exit. Uncheck it if you want to attach to a process, patch something there and exit debugger leaving the process to continue its run.
notes:
You have 2 possibilities for the end of debugging of an attached process: 1. detach (Ctrl+D), 2. terminate (Ctrl+T)
any explanation isn't necessary.
single step, fdbg executes 1 instruction exactly. This is done by set TrapFlag of the flags register. You can also change steps from "fine" steps to "larger" steps (only on branches) by Control -> Toggle DebugCtlMSR.BTF
for instruction call, loop, rep string operations (repz, repnz) fdbg places temporary breakpoint after instruction and executes run. Call, loop, rep operation finish without any extra action - in contrast with single step, when e.g. for rcx=8 repz movsb you have to do single step 8 times to finish it, or for call you have to step procedure till ret (return).
any explanation isn't necessary.
fdbg does it in this way: if thread caused debug event = fdbg catched it in WaitForDebugEvent
, then ContinueDebugEvent
is necessary to rerun it. If thread was paused using Pause (F11) or calling SuspendThread
, then ResumeThread
is necessary to rerun it.
This is done by telling the debug loop to continue with DBG_EXCEPTION_NOT_HANDLED
and it is useful only for special antidebugs based on exceptions by cooperation with Rambo -> Ignore_exceptions or for debugging your app's exception handler. Typical scenario for the second task is:
Note that when you do it for app without any exception handler installed, this made the application to terminate itself like in real life without debugger.
for more, see fdbg0023_samples\IgnoreExceptions\*.*
fdbg tries to scan memory of debuggee from thread RSP to the top of stack and find an address which may be return address from procedure (there should be a call instruction which saves the return address into the stack), if such address found, temporary breakpoint is put there and debuggee is run. software breakpoint type is used by default. if you want to defeat some antidebug trick you may force fdbg to use hardware breakpoint type instead of software breakpoint by setting on the menu Rambo -> CC collateral damage. note that this may not be ever ultimately accurate as some procedure with antidebug tricks may put some false addresses into the stack at lower RSP than is the qword holding real return address from procedure so fdbg finds the false address instead of correct return address - in such case debuggee runs and misses correct return address from procedure
This is done by putting temporary breakpoint and executing run. You are asked to enter address to execute to. You can also pick up the address directly from a symbol based on exports, see fdbg0023_samples\symbols_easy\*.* (you can also add extra hexa value into address of symbol).
This is done by putting temporary breakpoint and executing run. Instead of Alt-F9 you aren't asked to enter address... Ooooo maybe you have a feeling that there is something wrong, but the address is taken from selected address in code 1st or code 2nd. Thus one of them must be active (because fdbg uses WM_MDIGETACTIVE
to retrieve it), and address is taken from selected iItem (the only one having rectangle of focus or selection).
Please note that it is really big helper when debugging, just go where you want in code (PGUP, PGDOWN, arrows) and press F4 on desired instruction.
This is done by suspending the currently runnig thread (kernel32.SuspendThread
). SuspendThread
allows to increment suspend count more than once, but only one incrementing is enough for us.
Note that a thread is in resumed state until someone uses PAUSE or something call SuspendThread
or thread is created (CreateThread
) with dwCreationFlags=CREATE_SUSPENDED
and it is necessary to wait for its signaled state (WaitForSingleObject
) after CreateThread
... Debuggee = process(es) and thread(s) may be in resumed state and one of threads may be hung in debug loop (WaitForDebugEvent
) after causing debug event = it is hung between WaitForDebugEvent
and ContinueDebugEvent
. You can safely modify thread's registers in hung state and you needn't to do extra SuspendThread
. Modifying process' memory is unsafe if your process has more threads: one of threads could change memory between picking memory content and writing modified content.
puts temporary software breakpoint into a clean position in a code, removes any (permanent as well temporary) sw bp from a position in a code where SW BP is set. Conditions are the same as in run here (F4), so the position is determined from:
WM_MDIGETACTIVE
to determine it) - thus activate code 1st or code 2ndthis is done by replacing 1 byte of the debuggee memory with int3
instruction (byte 0CCh
). After executing int3
, debuggee stops and debugger is notified about breakpoint exception.
You can also pick up the address directly from a symbol based on exports, see fdbg0023_samples\symbols_easy\*.* (you can also add extra hexa value into address of symbol).
Note that SW BP is in memory, thus belongs to a process.
this is done by setting debug registers. It avoids to modify debuggee memory (in contrast of software breakpoint which overwrites 1 byte of memory with 0CCh
)
Note that hardware breakpoint uses debug registers, thus belongs to a thread. Fdbg manages HW BP in a different way than common debuggers. This way has some advantages (for common tasks) as well some disadvantages (for antidebug tasks). Fdbg sets identical content of debug registers to every thread as well to every newly created thread (immediately after receiving CREATE_THREAD_DEBUG_INFO
or CREATE_PROCESS_DEBUG_INFO
in fdbg debug loop). So the advantage is that after you once set HW BP then you won't worry whether any process is occupying the desired address or a process there is only going to create. The first disadvantage is that you can't use different debug registers in more threads (e.g. you can't set 12 HW BP for 3 threads). The second disadvantage is that some clever antidebug is able to modify the content of its own debug registers (yes, that's hard work, but is possible: 1. install exception handler, 2. cause exception, 3. exception handler modifies content of thread context, 4. exception handler gets thread handle by GetCurrentThread
, 5. exception handler writes debug registers of the thread context to the thread itself by SetThreadContext
with flag=CONTEXT_AMD64+CONTEXT_DEBUG_REGISTERS
).
Second note isn't much important, it's only one small surprise for uninformed man - HWBP generates debug exception (int01, the same as single step), it doesn't generate exception breakpoint (int3).
you may put a symbol or a name of an export from DLL for setting breakpoint there. the breakpoint is always set temporary (one-shot bp). the type of breakpoint is SW BP by default, if you want HW BP, you must enable Rambo -> CC collateral damage
shows you a lists of sw and hw breakpoints. To delete any, just double click on it. If you have a lot of SW BP, use button 'Wipe out all SW BP' to delete every SW BP. Fdbg supports 400h SW BP (if you need more, just modify MaxNumberOfBreakpoints
in fdbg_constants.inc
). For HW BP there isn't any button for lazy guys, everybody have to do at most 4 doubleclicks.
creates an edit control for address in code/data/stack SysListView (as left mouse dobleclick) so you can manually edit the begining address
note that Code/Data/Stack window must be active = "on the top"
without any mouse assistence, pressing Ctrl-Tab / Shift-Ctrl-Tab rotates among windows, or you can select the window from the face menu
Hint0: you can change the cursor position (begin/end) or the whole text selecting in the menu Face -> Various setting -> goto command edit style cursor
Hint1: if you are doubleclicking on the address too often to select the content, then you may set it automatically in the menu Face -> Various setting -> double clicking on item selects the content of the item also
shows you a list of processes and threads. Selected proc/thrd is the only one currently displayed (code, data, stack, registers). Double click on desired proc/thrd to display its code, data, stack, registers.
Note: hung means thread execution is stopped in debug loop between WaitForDebugEvent
and ContinueDebugEvent
. FDBG must call ContinueDebugEvent
to continue its execution. Suspended/Resumed means state after SuspendThread
/ResumeThread
.
shows you info from the stack of currently displayed process/thread. The most valuable is 'call stack'. Every call procedure leaves a trace in stack - return address from the procedure. Fdbg just checks values in the stack whether they points to an instruction following instruction of call. Thanks to this feature you can watch how much and which subprocedures were called and how much deeply you are in subprocedures tree. When an exception (bug) occures, you know the tree of called procedures and subprocedures which lead into exception. Search for 'called from' from current RSP and every parent procedure has its own record in the stack where subprocedure returns by RET instruction. Values under address of current RSP are usually useless, but may help in rare ocassions (they may or mayn't record return addresses of earlier and finished procedures, they don't belong to current procedures tree, they may be overwritten with fake values).
Stack call values are obtained in this way: fdbg reads qword value from stack, disassembles back the instruction on the address preceeding that value (=instruction which end is on the address equal to the value read from stack) and if the instruction is call then the value from the stack will be used for RET instruction to return from the call.
Double clicking on desired value copies the data of your interest into Log where you can select any part of it and copy it into clipboard using Ctrl-C.
shows you imported APIs from DLLs. You can sort items by clicking on one of both column headers of the SysListView32 (API name, address). Only ascendent direction is supported, reverse order isn't. According to the rules for DLL's exports, API names are sorted alphabetically in DLLs by default. So the only one other choice for sorting is by APIs' addresses. Double clicking with left rat's paw on SysListView32 copies the whole clicked "line" (both members: API_Name=iSubItem=0 and Address=iSubItem=1) into LogEdit so then you can pick addresses (1. select, 2. Ctrl-C) and e.g. put breakpoints there (Alt-F2)...
symbols are designed for easy translation of raw hexa address into label, variable_name, etc. in your source code. You really appreciate symbols if your source code is big enough and you have to quickly locate a bug (crash point). Debugger outputs hexa address of the bug in the executable and symbols are responsible to locate the closest label in your sources. You can search symbol only if you have compiled your application with debug support (fdbg doesn't support FASM debug symbols, but don't worry, read Varia for some tricks, or look into fdbg0023_samples\symbols_easy\*.*). This menu supports only MS COFF symbols, not export-type (from symbols_easy\*.* samples). Type address or symbol name into Edit Control. Uncheck checkbox if you want to scan only currently displayed process (you can switch process in Explore -> Processes and Threads). Leave it checked to scan the whole process' tree (every PID=ProcessID). Entered address is hexadecimal number without h-terminator (e.g. 4012AD), entered symbol name isn't case sensitive. Result has hexadecimal numbers, only line number in source file is decimal. Note: According to LiveKD strange bahaviour, microsoft symbols are disabled by default. You must enable MS COFF symbols in Face -> Various settings -> Allow MS COFF symbols
1st example of output:
SetROP2 Address=000000001C0014FAh PID=00000D90h ModBase=000000001C000000h Flags=00000000h Value=0000000000000000h Register=00000000h
SetROP2 Address=000007FF7FCA5090h PID=00000D90h ModBase=0000000000000000h Flags=00000200h Value=0000000000000000h Register=00000000h
2nd example of output:
DemoInit+00000005h Address=0000000000401175h PID=00000D90h ModBase=0000000000400000h Flags=00000000h Value=0000000000000000h Register=00000000h
f:\asm\prog\fasm64\p006\fdbg000c_samples\debug_symbols\dll\demo.c LineNumber=101 FirstInstructionAddress=0000000000401170h
3rd example of output:
StartSelection Address=000000001C001020h PID=000009D4h ModBase=000000001C000000h Flags=00000000h Value=0000000000000000h Register=00000000h
d:\asm\prog\fasm64\p006\fdbg000c_samples\debug_symbols\dll\select.c LineNumber=66 FirstInstructionAddress=000000001C001020h
you can search for string (max 8 characters long) or sequence of hexa bytes (max 8 hexa bytes) in debuggee. Result is shown in Log EDIT. If such string/sequence is found, Data 3rd start position is updated to point to the result.
notes:
Hint - look into Log EDIT for finding module's begin and end before you try to search through it.
shows you info about memory of the process using VirtualQueryEx
shortcuts are combinations of: NOACCESS Read Write Execute Copy Guard Nocache
double clicking with left rat's paw on SysListView32 copies the whole clicked "line" into LogEdit
you can save debuggee memory (=dump) as a binary file. You needn't to worry about software breakpoints, fdbg removes them immediately after reading memory from debuggee, thus memory dump is free of fdbg SW BP (1. read debuggee memory into a buffer, 2. restore bytes in the buffer at positions of SW BP, 3. write file from the buffer). Address and size are in hexa, but put them without h-terminator, e.g. 40012B.
Note - memory is saved from the desired address of currently displayed process.
you can load binary file into debuggee memory. You needn't to worry about software breakpoints, fdbg itself sets them into the debuggee just in the time of writing memory (1. read file into a buffer, 2. overwrite bytes in the buffer with 0CCh
at positions of SW BP, 3. write debuggee memory from the buffer). Address and size are hexa numbers as in memory save.
notes:
VirtualProtect
access flag) for more memory pages. You needn't to worry about writing more pages with different access flags in one action. E.g. loading end of code with read execute flag + begin of data with read write flag works fine. You can do it at once even for the whole image = header(readonly) + code(read_execute) + data(read_write) + ...playing games with branches
for AMD CPUs it works on all x64 versions of windows at the time of releasing this fdbg version, for Intel CPUs DebugControl (SingleStepOnBranches, LastBranchesRecording) feature was firstly implemented in windows 2008 server x64 R2 (the same kernel as windows 7 x64)
for more info about these features, read my presentation at 2nd FASM conference, Brno, Czech Republic, 2007-august-25, or go to www.amd.com, download 24593.pdf and read chapter 13.2.5 Control-Transfer Breakpoint Features
enable/disable recording of branches (the best and most ultimate but very small back trace "buffer"), it is very useful to enable it to know instructions executed before exception (few steps backward before a buggy crash in your program), stepping forward is very easy (just pressing F7 or F8), but it is very painful to obtain steps backward and this is a tool to help you a bit (note that you can restart debuggee and put a breakpoint at LastBranchFromIP / LastExceptionFromIP and repeat these steps few times so you can do more steps backward)
You can also try very small and easy fdbg0023_samples\branches\a00.exe, I strongly recommend you to read branches\a00.asm too. If you don't have so much time then only small note: if you are using HW_BP (or e.g. Rambo -> CC Collateral damage is on) then when HW_BP or Single Step occures (int01, debug exception), then get the address from LastBranchFromIP instead of LastExceptionFromIP - it is because CPU clears DebugCtlMSR.LBR when transfering control from the exception to exception handler of int01 so the important address stays in LastBranchFromIP and is not copied into LastExceptionFromIP (executing ICEBP instruction = opcode 0F1h also doesn't update the LastException registers because it calls int01 handler).
changes the behaviour of RFLAGS.TF, switches between "normal" and "larger" single steps for doing Trace into F7 ("larger" means steps only on branching instructions instead of on every instruction)
the main core of anti-antidebugs (fight against antidebugs).
it is done by CreateRemoteThread
which sets one byte at certain position indicating presence of debugger. Yes, another way is possible, by WriteProcessMemory
(ReadProcessMemory
qword at (ThreadLocalBase + 60h
)), write byte at returned address + 2, but this doesn't work immediately after CREATE_PROCESS_DEBUG_EVENT
(maybe OS refuses to send early debug events to the debugger when this byte is cleared so early exception causes EXIT_PROCESS
), but should work with create thread with small delay.
detecting this rambo fight is possible... so here one undetecteable manual way:
mov rcx,gs:[30h]
mov rax,[rcx+60h]
mov byte [rax+2],0
but how to obtain gs:[30h]... just grab the value ThreadLocalBase from the log window after creating a process or thread... simple, huh ?
hides fdbg against finding it by FindWindow
with WindowName
or ClassName
.
Note that it requires to restart fdbg. WindowName
is changeable easy without restart, but changing ClassName
requires restart to create it with another class. Generating of random class name has a little probability, that routine generates class name which is already registered and then fdbg doesn't start correctly - just restart it again.
if you request single step (Trace into F7) on PUSHF
instruction, fdbg puts temporary breakpoint on the next instruction and executes run (=fdbg does Step over F8). This prevents to push flags with TrapFlag=1 into the stack and thus detecting single stepping = debugging. You can even combine it with CC Collateral damage so HW BP is set to the next instruction instead of SW BP. See fdbg0023_samples\TrapFlag\a00.exe for testing this feature.
it is a usage of HW BP instead of SW BP if possible (don't forget the total limit of only 4 HW BP) - for Step over (F8), Return from procedure (Alt-F8), Excute to (Alt-F9), Run here (F4), Breakpoint at symbol, and at the time of CREATE_PROCESS_DEBUG_EVENT when setting a breakpoint at the process entry_point. It is useful for self modifying code, to calculate code-self-crc, for some antidebugs. If there is no space left for setting HW BP, setting a breakpoint falls back to normal way - setting SW BP).
You can try fdbg0023_samples\adbg\protected.exe to test this feature.
weapon against fdbg0023_samples\entrypoint\a00.exe which is based on image offset 0 in exe header, so win must place it at least at 10000h and the shift is the core of returning bad ThreadStartAddress.
weapon against fdbg0023_samples\TLS_callback\a00.exe
todays CPUs have hardware NoExecute prevention and I haven't find any way how to made bytes from executable header to be executable immediatelly after execution (before exe entry point). It was common trick in 32-bit word. Maybe somebody uncovered, is uncovering, will uncover how to turn CPUs protections off and then this feature begins to be usable. But I'm afraid that its todays usability is close 0. This feature supports headers of processes only, not headers of DLLs (if you want it for DLLs too, ask me for doing it, it's trivial to add support for DLLs). Once you set PE32+ header executable+writeable you can't reverse it (yeah, it is possible to do it easily, but fdbg doesn't support it yet - todays you have to uncheck this menu and restart debuggee).
some antidebug can install exception handler and cause exception, then its exception handler does some decrypting or so... You can simple tell fdbg not to handle exception and to send the exception to application's exception handler by Run unhandled (Ctrl-F12). But when antidebug wants to trigger exception 1000 times, it's easier to tell fdbg to ContinueDebugEvent
with dwContinueStatus=DBG_EXCEPTION_NOT_HANDLED
automatically.
Note that fdbg doesn't save list of exceptions which you want to ignore. These setting are lost after fdbg exits.
you may change page attributes, e.g. make read-only page writeable or make a page guarded (MEMORY_BASIC_INFORMATION.AllocationProtect = PAGE_GUARD), or make a page nonexecutable
it is useful when analysing infection to make newly allocated suspicious pages guarded to capture code execution or data access on them, after capturing exception shown in Log (ExceptionCode=80000001h=EXCEPTION_GUARD_PAGE) you may restore the original access protection of the page
guard pages act as one-shot access alarms
note that the access protection value can be set only on committed pages (the column State must show commit)
it is similar to IsDebuggerPresent fight but this menu directly erases the PEB bit indicating debugging (IsDebuggerPresnt fight uses remote thread to erase it which is automatical but cannot be used in every case, try fdbg023_samples\entrypoint\a03.*)
choose font, its size and other parameters. Recommended fonts are: Terminal, Lucida Console. You can adjust font width in face -> various settings (see below).
LOGFONT.lfHeight
, you can adjust LOGFONT.lfWidth
here. Suitable especially for small fonts with bad visibility at high screen resolution. Don't hesitate to experimentate with several settings to find the font size suitable for you. For font Terminal of size 6 try differences between width 0 and 5.WS_BORDER
style.WS_EX_CLIENTEDGE
style.WS_BORDER
style, you may want to have thicker items in SysListView32, else edited text doesn't fit into edit control.WS_EX_CLIENTEDGE
style.WM_MEASUREITEM
when
CreateWindowEx
of SysListView32 with LVS_OWNERDRAWFIXED
style.rip
at every step. Having 0 here is necessary when tracing some antidebugs which obfuscate code by jumps into middle of disassembled instructions like code sequence EB FF C3. If you have 0 here, the first starting instruction is always accurate no matter obfuscation by adding messing data / misleading jumps into code. Please note that you can turn on logging (in Log window) single steps trace into (F7) and step over (F8) by unchecking above checkboxes Don't log breakpoints/single steps.here you can select any of the children windows, or alternatively, Ctrl-Tab / Shift-Ctrl-Tab rotates among them (Code, Data, Stack, Registers, Log)
launch the help which you are reading now.
Double click with left rat's paw on allowed item creates an edit control for you be able to change register/memory. Allowed changes are:
Notes:
RSP
register).rax
, rbx
, rcx
, rdx
, rsp
, rbp
, rsi
, rdi
, r8
, r9
, r10
, r11
, r12
, r13
, r14
, r15
, rip
(entering rip
/rsp
is quick way to jump in current rip
/rsp
in code/stack if your pointer is faraway).Hint0:
For editing address in Code/Data/Stack you can use the goto command (Alt-G)Hint1:
If you are double clicking too often and then selecting the content of the Item by doubleclick again (so by 4-click), you may reduce the count of clicks in the menu Face -> Various setting -> double clicking on item selects the content of the item alsoright rat's paw clicking on SysListView32 opens menu where you have only 1 choice to select - copy the content of the whole SysListView32 into the clipboard. Window owning the SysListView32 needn't to be active, only small visible part of the SysListView32 is enough to click there. Clicking doesn't activate the window, just opens the huge menu.
Note, that you can't get memory/register of process/thread in the time when it is resumed and not hung in debug loop.
You can see various colors in code SysListView32. They indicate instruction pointer or breakpoint(s) on the instruction. When more events occur on the same position, colors are combined together. Coloring is a job for a routine catching WM_DRAWITEM
notification for the SysListView32 created (CreateWindowsEx
) with LVS_OWNERDRAWFIXED
style.
Notes:
int3
, int3
, db 0CCh
in your apps source).For code/data/stack use PageUp/PageDown for move 1 page, up/down
arrow 1 line (it means 1 instruction in code, 16 bytes in data, 1 qword in stack), left/right arrow 1 byte. If you want to move further, double click on any address and type the desired address into the edit control.
Notes:
Yeah, perhaps your first thought was: fdbg makes dual-core CPU from my single-core... but you aren't right. Both 2 windows look into the same code, you may use one for keeping watching the current RIP
(instruction pointer) and the other for looking faraway from RIP
. Code 1st is updated every exception (exception, single_step, breakpoint), start address in Code 2nd stays untouched untill you change it. Code 2nd is useful to watch several previous addresses, but it losts last instruction if there is a big jump in the code. If you want to watch more addresses executed before current one, then uncheck checkboxes Don't log exceptions, Don't log breakpoints, Don't log single steps in Face -> Various settings + you can set there the number how much instructions to disassemble back in Code 1st every step.
Data may be displayed in various formats: qwords, dwords, words, bytes. To rotate among them, click on any column header of SysListView32 in Data 1st, Data2nd, Data 3rd - that is e.g. on any of these strings: address, +0 +2 +4 +6, +8 +A +C +E, ASCII
Status window (on the bottom of fdbg) shows you the state of the currently displayed thread. If the state is running, you can do only 4 things: wait for thread completes, kill thread (Debuggee -> Terminate Ctrl-T, Exit fdbg Alt+X), Pause F11 thread, switch to another thread (Explore -> Processes and threads -> double click on another thread). If the state is stopped, you can modify registers/memory, execute Single Step, Step Over, Run, ... Stopped means that thread is hung in debug loop (after WaitForDebugEvent
before ContinueDebugEvent
) or stopped because SuspendThread
, CreateThread
/CREATE_SUSPENDED
until WaitForSingleObject
. Running means that thread executes (read ResumeThread
in microsoft API documentation).
We will discuss some tricks here.
You can easy make symbols by making exports in exe (the same as in DLLs) - see fdbg0023_samples\symbols_easy\*.*
These symbols aren't show in Explore -> symbols (Ctrl-S), they are shown only in code window.
There are 2-3 possible choices how to find the position of a bug in the source without using debug symbols (how to transform address in fdbg into near label in source code):
rip-20
or at address rip-21
or rip-22
, ...db 0cch
= int3
into your source code, recompile it and Run F9 under fdbg again. Watch whether breakpoint or bug appears as the first. If breakpoint appears the first, then move it further and further from the entrypoint to go closer of buggy instruction untill bug causes the exception first (=before breakpoint). Then the bug is between current and previous position of db 0cch
in the source code.lea rax,[any_label_from_source]
(7-bytes instruction) at entrypoint (the first instruction to execute) of the program. Recompile the program. Load under fdbg. Compare the address after lea instruction in code 1st with the address of bug obtained previously. The first instruction is transformed into an address so now you can compare whether the label address is below, above and how much close to the address of the bug. The increasing of code by 7 bytes by putting lea rax,[...]
isn't much important, but may cause rare disappearing of the bug (especially may cause align 16 of accessing xmm registers with instructions: movdqa
, movaps
, movapd
when they read from the code and not from aligned data - e.g. by calculating self-crc check of the code...). Then change lea rax,[any_label_from_source]
to another label (or the name of a procedure), do the same and reload program under fdbg again. Watch whether hexa value in lea rax,[hexa_value]
is closer to the address of the bug.The trick with putting db 0cch
into the source may be used as a way of quick and direct (without long stepping) jump into the code supposed not to do what you want for it to do. Put int3
= db 0cch
into your source just before the instructions you want to examine, then recompile it, load under fdbg and use Run F9. Execution stops after breakpoint trigger in your code at required position. Don't forget to remove db 0cch
and recompile the program before you release it to usage, else it crashes because there isn't any debugger as its parent to catch the exception generated by db 0cch
(int3
).
method for capturing unpacked/decrypted executable:
most of console programs call GetStdHandle, WriteFile at the early begin of their execution, most of GUI programs call GetModuleHandleA, GetModuleHandleW, DialogBoxParamA, DialogBoxParamW, RegisterClassExA, RegisterClassExW, CreateWindowExA, CreateWindowExW
so you can easily uncompress/decrypt an executable by doing these 4 steps: