BINARY PATCHING
this method is used flip the logic of a program to the more interesting parts of the code.
#C SAMPLE CODE SNIPPET
root@dev:~$ visualstudio > 14_scanf_error_check.c
#include <stdio.h>
int main()
{
int x;
printf("Enter X:\n");
if(scanf("%d", %x)==1)
printf("You entered %d...\n", x);
else
printf("Woof.\n");
return 0;
}
PS C:> cl /MD /Od /Zi /FA 14_scanf_error_check.c
* ALT: cl /MD /Od /Zi /FA /Fa14_scanf_error_check_x64 /Fe14_scanf_error_check_x64 /Fo14_scanf_error_check_x64 14_scanf_error_check.c
#in this examples, binary patching will be used to display BOTH
#output of the printf statement regardless of whether the user input is valid
#aside from this, the main point is to make the changes persistent
#step 1: big picture overview
root@dev:~$ ghidra binaryWDebugSymbols.exe
ghidra > function graph
* get an big picture overview of what the program is doing
- e.g, in this particular example, the program is accepting user input
and displays whether one of two actions/output is followed (if/else)
#step 2: locate the main()
#step 3: locate the first compare instuction then patch instruction to ensure that no matter what, the comparison will always be equal!
140001033 83 f8 01 CMP EAX, 0x1 //change 0x1 to EAX to the instruction will become EAX, EAX
#step 4: patch instruction
ghidra > listing window area > right-click on the instruction (CMP EAX, 0x1 > patch instruction > OK
140001033 39 c0 CMP EAX, EAX
140001035 01 ?? 01h // change this to NOP
* comparing the value against itself will always lead to equality; hence, the next jump instruction
won't occur - this ensure that the instruction is always executed
* when patching instruction, the instruction must either be the same number of bytes or less IOT not overwrite the rest of the code
- must use NOP if less
#step 5: view instruction info
ghidra > listing window area > right-click on the instruction 140001033 39 c0 CMP EAX, EAX > instruction info
#step 6: patch extra byte w/ NOP
ghidra > listing window area > right-click on the instruction 140001035 01 ?? 01h > patch instruction
NOP
140001035 90 NOP //this is a valid instruction that means "carry on"
* in the decompiler view, you should notice that the "if" instruction has disappered
#step 7: continue patching until the else statement is removed - this can be done two ways
#method 1: change the JMP instruction to go elsewhere or method 2: patch using one or more NOP instruction!
ghidra > listing window area > right-click on the instruction 140001049 eb 0d JMP LAB_140001048 > patch instruction
change: 140001049 eb 0d JMP 14000104b
* this change jumps to the label LAB_14000104b XREF(1): 140001036(j)
14000104b 48 8d LEA _Argc,[s_woof._140006024].
#step 8: save the binary as a patched executable
#method 1:
ghidra > File > Export Program
Format: PE
Output File: patchedExecutable.exe
#method 2: ghidra script
ghidra > Display Script Manager > Manage Script Directories > + > Desktop\git-sre\resources\
* this will import the "binary_export.java" script into ghidra
ghidra > Display Script Manager > Binary > right-click binary_export.java > Edit with basic editor
* this file may need to be edited if ghidra displays a warning
- change Binary_Export in public class... to "binary_export" - lowercase.
ghidra > Display Script Manager > double-click on binary_export.java
Filename: scriptPatched.exe
Type: All Files (*.*)
PS C:\> .\patchedExecutable.exe
Enter X:
123
You entered 123...
woof.
PS C:\> .\patchedExecutable.exe
Enter X:
c
You entered 0...
woof.
PS C:\> .\scriptPatched.exe
Enter X:
c
You entered 0...
woof.
root@dev:~$ ghidra binaryWODebugSymbols.exe
* re-create and re-compile with and w/o debug symbols and identify the main entry point
as practice
-
Last updated