Skip to content

Latest commit

 

History

History
226 lines (202 loc) · 11.8 KB

reversing.md

File metadata and controls

226 lines (202 loc) · 11.8 KB

+

methodology

vm

scripting dissassembly

side channels

  • timing attacks - On password validation routine, when a char is correct, more instructions are executed
  • syscall counting - strace | sort | uniq -c
# instruction counting
~/opt/dynamorio/build/bin64/drrun -c ~/opt/dynamorio/build/api/bin/libinscount.so -- ./a.out \
    | awk '/Instrumentation results:/{print $3}'
qemu-x86_64 -d in_asm ~/a.out 2>&1 \
    | awk '/IN:/{i+=1} END{print i}'
gcc -O0 a.c && echo 'a' \
    | perf stat -e instructions:u ./a.out 2>&1 \
    | awk '/instructions.u/{print $1}'

# bruteforcing chars
for n in {32..127}; do
    c=$(awk '{ printf("%c", $0); }' <<< $n)
    printf '%s ' $c
    ~/opt/dynamorio/build/bin64/drrun -c ~/opt/dynamorio/build/api/bin/libinscount.so -- ./a.out <(printf '%s' $c) | awk '/Instrumentation results:/{print $3}'
done 2>/dev/null | vim -
# - [Counting instructions using Stalker · Issue \#94 · frida/frida\-python · GitHub](https://github.com/frida/frida-python/issues/94)
# - https://stackoverflow.com/questions/22507169/how-to-run-record-instruction-history-and-function-call-history-in-gdb
# - https://stackoverflow.com/questions/8841373/displaying-each-assembly-instruction-executed-in-gdb/46661931#46661931
# - https://en.wikibooks.org/wiki/QEMU/Invocation

# coverage
~/opt/dynamorio/build/bin64/drrun -t drcov -dump_text -- ./a.out
diff -Nauw drcov.a.out.2575073.0000.proc.log drcov.a.out.2575098.0000.proc.log | vim -
# - diff alternative: `lighthouse` plugin
# - https://stackoverflow.com/questions/53218160/how-can-i-do-code-path-analysis-in-a-debugger
# - https://dynamorio.org/dynamorio_docs/page_drcov.html

# ||
# 1. grep xrefs from asm dump, take addresses
# 2. make gdb script with temporary breakpoint (`tbreak`) foreach address
# - [On why my tbreak tracing trick did not work \- gynvael\.coldwind//vx\.log](https://gynvael.coldwind.pl/?id=638)

# execution trace
~/opt/dynamorio/build/bin64/drrun -c ~/opt/dynamorio/build/api/bin/libinstrace_x86_text.so -- ./a.out
# ||
pin.sh -t obj-intel64/instat.so ./a.out
# ||
qemu-x86_64 -d in_asm a.out
# ||
# - https://man7.org/linux/man-pages/man1/perf-intel-pt.1.html
# - https://perf.wiki.kernel.org/index.php/Tutorial#Source_level_analysis_with_perf_annotate
perf script --call-trace
perf script --insn-trace --xed -F+srcline,+srccode
perf trace record
# ||
# - ~/code/snippets/instrace.gdb
# - x64dbg - https://help.x64dbg.com/en/latest/gui/views/Trace.html#start-run-trace
#     - Trace view > Start Run Trace
# - IDA Pro - https://reverseengineering.stackexchange.com/questions/2486/is-there-an-equivalent-of-run-trace-as-in-ollydbg-for-ida-pro
#     - Debugger > Tracing > Function Tracing
#     - Debugger > Tracing > Instruction Tracing
#     - Debugger > Switch Debugger... > Trace replayer
# - https://github.com/teemu-l/execution-trace-viewer

clean room design

case studies

  • FwordCTF 2020 - XO
    • strlen side-channel on flag xor - use dummy values as previous chars while guessing next char, since a right char generates a null byte, making strlen ignore next chars after the right char

binary patching

  • Skype version check

    The issue is that skype stopped supporting old version, and I am forced to use web skype, or new skype for linux which doesn't meet my expectations. When I launch old skype login screen pops, I enter my credentials and after clicking 'login' skype just exits. Fortunately, Microsoft has implemented the program version verification in a particularly simple way.

    sed -i 's/4\.3\.0\.37/8.3.0.37/g' skype
  • Mattermost phone-home

    [...] versions of Mattermost have phone-home to segment.io embedded in the server, which can be disabled with the undocumented and exceedingly misleadingly-named 'MM_LOGSETTINGS_ENABLEDIAGNOSTICS=false' var in the env. I made a Dockerfile that actually patches out the spying in the binary using sed, rather than figure out how to rebuild it without it or trust that the env vars work.

    dockerfileLines:
        - FROM mattermost/mattermost-team-edition@$$cap_mattermost_version
        - RUN sed -i 's#api.segment.io#xx.example.com#gI' /mattermost/bin/mattermost
        - RUN sed -i 's#securityupdatecheck.mattermost.com#xxxxxxxxxxxxxxxxxxxxxx.example.com#gI' /mattermost/bin/mattermost
  • Singleton initialization causes infinite loop
    • Win32 Disk Imager / Bugs / #85 If Google File Stream is loaded, win32DiskImager Crashes on Startup
    • dissassembly
      • offset 0x3bfd = virtual 0x47fd
      • byte 0x74 to 0xeb = je to jmp
    • decompilation
      BVar3 = DeviceIoControl(param_1,0x2d0800,(LPVOID)0x0,0,(LPVOID)0x0,0,&local_44,(LPOVERLAPPED)0x0);
      // Before patching
      if (BVar3 == 0) {
        return 0;
      }
      // After patching
      return 0;
    • DeviceIoControl

      If the operation completes successfully, the return value is nonzero. If the operation fails or is pending, the return value is zero. To get extended error information, call GetLastError. https://docs.microsoft.com/en-us/windows/win32/devio/calling-deviceiocontrol

    • translating control code 0x2d0800
    • actual issue: DeviceIoControl() error handling logic gets a singleton via MainWindow::getInstance() while it's constructor is still executing, causing another constructor call, and another DeviceIoControl() call, which will enter the same conditional branch again in a loop, until a stack overflow occurs.
      • stack trace (read from bottom to top)
        ntdll!NtDeviceIoControlFile+c
        KERNELBASE!DeviceIoControl+40
        kernel32!DeviceIoControlImplementation+4b
        Win32DiskImager+4f38
        Win32DiskImager+672a
        Win32DiskImager+cd65
        --- [Loop end]
        Win32DiskImager+4d2d
        Win32DiskImager+5083
        Win32DiskImager+672a
        Win32DiskImager+cd65
        [...]
        Win32DiskImager+4d2d = GetDisksProperty() -> QMessageBox::critical(
                MainWindow::getInstance(),
                QObject::tr("File Error"),
                QObject::tr("An error occurred while getting the device number.\n"
                        "This usually means something is currently accessing the device;"
                        "please close all applications and try again.\n\nError %1: %2").arg(GetLastError()).arg(errText));
        Win32DiskImager+5083 = checkDriveType() -> GetDisksProperty(hDevice, pDevDesc, &deviceInfo)
        Win32DiskImager+672a = MainWindow::getLogicalDrives() -> checkDriveType(drivename, &pID)
        Win32DiskImager+cd65 = MainWindow::MainWindow() -> getLogicalDrives();
        --- [Loop begin]
        Win32DiskImager+58dc = main() -> MainWindow* mainwindow = MainWindow::getInstance();
        Win32DiskImager+10212
        Win32DiskImager+1825d
        Win32DiskImager+13e2
        kernel32!BaseThreadInitThunk+19
        ntdll!__RtlUserThreadStart+2f
        ntdll!_RtlUserThreadStart+1b
        
      • tools used: procexp to take a memory dump, Debug Diagnostic Tool to inspect stack trace and memory allocations, x32dbg to break on previously identified loop addresses