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