Choose IDA Debugger#
IDA supports multiple debuggers.
Supported debuggers in IDA
Select the Local Windows debugger.
Open the menu bar Debugger - Debugger Options to set some debugger features.
IDA debugger options
Debugger Interface Features#
Check Pause at process entry point
, select event conditions, and click OK.
Rename and change the color of the previous key code jinx.
After modification, press the X key to see where this function is referenced:
Color the reference points.
Set a breakpoint at 0x00401243, hover the mouse over this line, right-click - Add Breakpoint, and it will turn red after adding the breakpoint.
Through the menu bar Debugger - Start Process (F9)
, start debugging. If debugging a local executable, a warning window will pop up.
Note:
When analyzing the loader program, the program will not execute locally, but debugging is different. If the program is a virus or other dangerous malware, special caution is required. In this case, a remote debugger needs to be used to execute the program in a virtual machine.
Click Yes
to continue debugging.
Since the debugger is set to pause at the entry point, as shown below, IDA pauses at the entry point (0x00401000).
Adjust the general registers and flags register window in the upper right corner for viewing.
In the above image, the values of these registers can be seen. After adjusting normally, open the menu bar Window - Save Desktop
and check the default
option to save as the default window settings for the debugger. After that, when running the debugger, the program will run according to the default settings, which can also be modified if needed.
A stack view can be placed below the general registers.
On the left and at the bottom are the disassembly and hexadecimal windows.
Below the disassembly view is the current memory address and file offset, which refers to the executable file offset.
In IDA, the default G key is a shortcut to jump to a memory address. Press G and enter 0x401389 to jump to the previously set breakpoint.
All static analysis, renaming, and other changes will be saved.
Open the menu bar View - Open Subview - Sections, and find that the loader has loaded 3 sections.
Loaded the code field at 0x401000, as well as the data and .idata fields below. Modifications to these sections will be saved, while modifications to other sections will not be saved, as they are sections loaded by the debugger and will not be saved to the IDA database.
The L flag in the above image indicates that this program is loaded by both the loader and the debugger, allowing for static analysis while not losing static analysis information during dynamic debugging.
Below are some small toolbars.
- Menu bar View - Toolbars - Jump, then use the Save Desktop feature to set it as default enabled.
Press the back key to return to the previous program entry point.
In the menu bar Debugger - Breakpoints - Breakpoint List, you can view all program breakpoints.
Clicking on any point will jump to the corresponding breakpoint.
Conditional Jump Instructions and Flags Register#
The debugger is currently at the program entry point and has set two breakpoints. Press F9 to continue running.
At this point, the crackme.exe program is running, and the target program Help - Register menu bar prompts for username and password.
Click OK.
In the above image, the flashing red arrow on the left indicates the path the program continues to execute. At this time, the value of eax is 0x6c.
0x6c converted to a string is l.
In the above image, the al register is compared with 0x41 to check if it is less than 0x41 (A), and the al register is also compared with 0x5a in the green code block below.
asm | condition | operation |
---|---|---|
JA | z=0 and c=0 | jump if above |
JAE | c=0 | jump if above or equal |
JB | c=1 | jump if below |
JBE | z=1 or c=1 | jump if below or equal |
JC | c=1 | jump if carry |
JECXZ | ecx=0 | jump if ecx is 0 |
JE | z=1 | jump if equal |
JZ | z=1 | jump if zero |
JNE | z=0 | jump if not equal |
JNZ | z=0 | jump if not zero |
JO | overflow | jump if overflow |
JP | even parity | jump if parity |
JPE | even parity check | jump if parity even |
JNP | odd parity | jump if not parity |
JPO | odd parity check | jump if parity odd |
JS | sign bit = 1 | jump if sign |
JNS | sign bit = 0 | jump if not sign |
JL/JNGE | sign bit = overflow | jump if less or not greater/equal |
JLE/JNG | z=1 or sign bit = overflow | jump if less or equal/not greater |
JG/JNLE | z=0 and sign bit = overflow | jump if greater/not less or equal |
Conditional Jump Instructions and Jump Conditions
Next, switch to the IDA flags register view, as shown below.
According to the table, if CF=0, then do not jump, and the program executes towards the green code block. So what is the mathematical condition that triggers this C flag?
The C flag indicates that there was an error in unsigned integer operations. If we consider the cmp instruction as a subtraction that does not save the result, then 0x6c - 0x41 = 0x2b
, the result is positive. If al is 0x30, then 0x30 - 0x41 = -0x11
.
-0x11 is a negative number, and the program can only continue to run it in its corresponding hexadecimal form.
As shown in the image, -0x11 in hexadecimal is 0xffffffef, and in decimal, it is 4294967279, which is a large value, and 0x30-0x41
will not be positive.
So how do we know if the operation considers the sign? This depends on the type of jump used. JB is used for jumps after unsigned number comparisons, while the corresponding signed number instruction is JL.
When using the JB instruction, it is typically used to check if an unsigned integer is less than a certain value. If the operation results in a borrow, it indicates that the second operand (the number being compared) is greater than the first operand (the comparison number). At this point, the JB flag is set to 1, allowing the jump. Otherwise, if the operation does not produce a borrow, the JB flag is 0, meaning the condition is not met, and no jump occurs.
Example:
mov al, 150 ; Assign 150 to al
cmp al, 255 ; Compare al and 255
jb smaller ; If al is less than 255, jump to smaller label
; Execute other operations
smaller:
; If al is less than or equal to 255, it will jump here
In this example, if the value in al is less than 255, the CF flag will be 1, and it will jump to the smaller label. Otherwise, if the value in al is greater than 255, the CF flag will be 0, and it will not jump, executing other operations. (In summary, if al is less than 255, then jump)
To determine if the comparison is signed, it needs to be identified by the subsequent conditional jump instruction.
Unsigned Jump
Sign | Description | Flags |
---|---|---|
JE/JZ | Jumps if equal or zero | zf |
JNE/JNZ | Jumps if not equal or zero | zf |
JA/JNBE | Jumps if above or not below or equal | zf,cf |
JB/JNAE | Jumps if below or not above or equal | cf |
JBE/JNA | Jumps if below or equal or not above | cf,af |
Unsigned Jump
The instructions in the above image do not consider the sign, and each jump has a corresponding signed jump.
Sign | Description | Flags |
---|---|---|
JE/JZ | Jumps if equal or zero | zf |
JNE/JNZ | Jumps if not equal or zero | zf |
JG/JNLE | Jumps if greater or not less or equal | zf,sf,of |
JGE/JNL | Jumps if greater or not equal or less | sf,of |
JL/JNGE | Jumps if less or not greater or equal | sf,of |
JLE/JNG | Jumps if less or equal or not greater | zf,sf,of |
Signed Jump
In the two images above, JE (if equal)
appears in both images because in this special case, the sign does not matter. If the two numbers are equal, zf=1
, indicating that the flag is triggered. In signed jumps, JG = Jumps if greater
, while in unsigned jumps, the corresponding instruction is JA, Jumps if above
.
Continuing to debug the program, IDA will pause at each set breakpoint. A loop is executed, and each loop reads a character of the username input in the target program and compares it with 0x41. If any character is less than 0x41, an error will be reported. Since the input is lca, each value is greater than 0x41, so no error is displayed.
Try entering a number to see.
At this point, it jumps to the red block, which is the jb jump location, because the first character compared is 2 (0x32), which is definitely less than 0x41.
The C flag is also triggered, CF=1, because 0x32 - 0x41 is a negative result when subtracting unsigned numbers, which will trigger the C flag.
Right-click on the C flag and select Zero Value to clear the C flag to 0.
Press F9 to continue the process. The program reads the second character of 22lca, and the left red arrow starts flashing again. Continue to set the CF flag to 0; the subsequent characters lca will all be greater than 0x41, and the flag will not be triggered, and the program will follow the left red arrow.
After character detection is complete, the program reaches the last jump.
In the above image, the cmp instruction compares eax and ebx, and jz checks if they are equal, unsigned. The program goes towards the red block because these two registers are not equal.
Since they are not equal, the zf flag is not triggered.
If the zf flag is manually triggered, changing the jump direction, the program will turn towards the green block, indicating successful registration.
SET IP#
Set IP is only available in debugger mode.
Sometimes you can also not directly modify the jump; you can move the mouse to the code block you want to execute, right-click, and select SET EIP.
At 0x40124c, set eip, and the program will start running from 0x40124c.
Note: In version 7.7, performing this operation multiple times will result in the following error:
Prompting "Attempt to execute an illegal instruction."
The error message indicates that the memory is not writable, and perhaps the read content exceeds the range.
Summary#
By using the IDA debugger, dynamic debugging and static analysis can be performed to gain an in-depth understanding of the program's structure and execution process. However, this chapter does not modify the source program, only changing the values of the flags register in the debugger.