encrypted binary integrity checking with anti debug POC

A place to submit all custom code, scripts, and programs.
Forum rules
Do NOT post malicious code or programs. Please review all code posted in this forum before downloading or running any of the code or programs here.

encrypted binary integrity checking with anti debug POC

Post by MadM0use on Wed Jun 03, 2015 3:23 am
([msg=88305]see encrypted binary integrity checking with anti debug POC[/msg])

So, what if I told you you can have integrity checking to prevent patching, AND anti debug both as SIDE EFFECTS of an encryption scheme? Prepare for one of the coolest concepts to come to my brain on the toilet yet lol xD

Here is the code:

integrity.s
Code: Select all
;// ------------------------------------------------------------------------------
;// THE BEER-WARE LICENSE (Revision 43):
;// <aaronryool@gmail.com> wrote this file. As long as you retain this notice you
;// can do whatever you want with this stuff. If we meet some day, and you think
;// this stuff is worth it, you can buy me a beer in return
;// ------------------------------------------------------------------------------

[bits 32]
section .text
global _start

org 0x08048000
ehdr:                                      ; Elf32_Ehdr
   db 0x7F, "ELF", 1, 1, 1, 0         ;   e_ident
   times 8 db      0
   dw 2                               ;   e_type
   dw 3                               ;   e_machine
   dd 1                               ;   e_version
   dd _start                          ;   e_entry
   dd phdr - $$                       ;   e_phoff
   dd 0                               ;   e_shoff
   dd 0                               ;   e_flags
   dw ehdrsize                        ;   e_ehsize
   dw phdrsize                        ;   e_phentsize
   dw 1                               ;   e_phnum
   dw 0                               ;   e_shentsize
   dw 0                               ;   e_shnum
   dw 0                               ;   e_shstrndx
   ehdrsize equ $ - ehdr

phdr:                                      ; Elf32_Phdr
   dd 1                               ;   p_type
   dd 0                               ;   p_offset
   dd $$                              ;   p_vaddr
   dd $$                              ;   p_paddr
   dd filesize                        ;   p_filesz
   dd filesize                        ;   p_memsz
   dd 7                               ;   p_flags
   dd 0x1000                          ;   p_align
   phdrsize equ $ - phdr
_start:
   jmp code
begin:
   pop esi            ; pop the address of our data
   mov ecx, 36         ; set loop count to the size of the encrypted data
   xor eax, eax
   xor ebx, ebx
decode:
   mov al, byte [_start+ebx]      ; load character from key into al
   xor byte [esi], al            ; xor the key with the encrypted code
   inc esi                     ; increment our address
   inc ebx                     ; increment our secondary counter
loop decode
   jmp hello
   db 0x9c, 0xc8, 0x96, 0x5a, 0xb4, 0x8e, 0x5f   ; garbage filler because the key code is smaller than 36 bytes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; encrypted code:
code:
   call begin
hello:
   db 0x00,0x0e,0x07,0x88,0xe4,0x31,0xdb,0x31
   db 0xe3,0x70,0x35,0x68,0x8b,0x31,0x58,0x4d
   db 0x84,0xe3,0x21,0xee,0xac,0xbc,0x1d,0x0b
   db 0x83,0x69,0xf0,0xa4,0xf9,0x7a,0xc3,0xe1
   db 0x2d,0x84,0xb8,0xf5
;_start:
;   jmp hi
;main:
;   pop ecx
;   xor eax, eax
;   xor ebx, ebx
;   xor edx, edx
;   mov al, 0x4
;   mov bl, 1
;   mov dl, 12
;   int 0x80
;   jmp end
;hi:
;   call main
;   db "hello world", 0xa
;end:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; exit
   xor ebx, ebx
   xor eax, eax
   inc eax
   int 0x80
 
filesize equ $ - $$



generate.c
Code: Select all

//
// A program that generates encrypted executable code
//   Written by: MadMouse

#include <stdio.h>
#include <unistd.h>

int main(void)
{
   const char evil[] = \
   "\xeb\x11\x59\x31\xc0\x31\xdb\x31\xd2\xb0\x04\xb3\x01\xb2\x0c\xcd"
   "\x80\xeb\x11\xe8\xea\xff\xff\xff\x68\x65\x6c\x6c\x6f\x20\x77\x6f"
   "\x72\x6c\x64\x0a";
   const char key[] = \
   "\xeb\x1f\x5e\xb9\x24\x00\x00\x00\x31\xc0\x31\xdb\x8a\x83\x54\x80"
   "\x04\x08\x30\x06\x46\x43\xe2\xf4\xeb\x0c\x9c\xc8\x96\x5a\xb4\x8e"
   "\x5f\xe8\xdc\xff"
   ;
   
   int i;
   
   printf("\n\t; encrypted code:\n\tdb ");
   for(i=0;i<sizeof(evil)-1;i++)
   {
      printf("0x%02x",0xFF&(key[i]^evil[i])); // xor the curretn key byte with the current evil byte
      if(i!=sizeof(evil)-2)printf(",");   // maintain fluff
   }
   printf("\nsize: %i\n\n",i);   // print out the size so that we can set up offsets later
   
   return 0;   // WOOOT, all done ;)
}



secret.s
Code: Select all
[bits 32]
section .text
global _start
_start:
   jmp hi

main:
   pop ecx
   xor eax, eax
   xor ebx, ebx
   xor edx, edx
   mov al, 0x4
   mov bl, 1
   mov dl, 12
   int 0x80
   jmp end

hi:
   call main
   db "hello world", 0xa

end:


Makefile
Code: Select all
all:
   nasm -f bin -o integrity integrity.s
   chmod +x integrity

secret:
   nasm -f elf secret.s


generateasm:
   gcc generate_asm.c -o generate
   ./generate


Now I will show you how to make it, then we will talk about WHY everything WORKS

First we write our secret encrypted code:

Image

Ok, so this is just a basic (mostly) position independent hello world assembly snippet, I dont care to explain the basic bits, but after the system call to write, you see we jump over the "hello world" data, into nothing. this is done because directly after the encrypted code chunk in integrity.s, we call more code, in this case a system call to exit.

Now that we have our secret code, we need to turn it into encrypted secret code, here is a picture walkthrough on that process with a little script i wrote a LONG while back for generating shellcode.

The script:
Code: Select all
###############################################################################
# A shellcode extractor
# written by madmouse
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 43):
# <aaronryool@gmail.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return Aaron R. Yool
# ----------------------------------------------------------------------------

echo -ne '\n\n// C/C++\nconst char evil[] = "';
for i in $(objdump -d $1 -M intel |grep "^ " |cut -f2);
   do echo -n '\x'$i;
done;echo -e '";\n\n'

echo -ne '# Python\nevil = "';
for i in $(objdump -d $1 -M intel |grep "^ " |cut -f2);
   do echo -n '\x'$i;
done;echo -e '"\n\n'

echo -ne '# Bash\n./shellcode $(echo -en "';
for i in $(objdump -d $1 -M intel |grep "^ " |cut -f2);
   do echo -n '\x'$i;
done;echo -e '")\n\n'



Ok, so first we extract the byte code with that utility script, you may also do this by hand one of two ways, using objdump, or assembling with nasm using -f bin and then using hexdump.
Image

now we take that C code, and plug it in under evil inside generateasm.c
Image

next, we assemble what little we have written in integrity.s, with included filler bytes or more code in between. then we run readelf, get our entry point, and dump that section of byte code out with the calculated number of bytes into key.bin:
Image

then we pipe that file into hexdump to extract the byte code manually:
Image

then we plug that in under key in generateasm.c, then we run it to generate our encrypted code:
Image

plug that shit into the encrypted code area:
Image

AND WE ARE DONE!!!!

lets see what it does, and talk about why it does lol

base run to prove it runs lol:
Image

now we fire up gdb, and see if we cant just set a break point at the jmp after the decryption loop, and run the program the same way:
Image

OH NO, WE CANT. because breakpoints are set IN MEMORY thus corrupting our encryption key, making that encrypted code USELESS. if you were to patch this binary, it would make things far worse.

now, you can take this cncept, and blow it up into a REAL situation, and do a few things:

you can use signal handlers to catch segfaults, and other exceptions, then take those bastard reverse engineers on a joy ride to hell.

you can set this up in a chain of encrypted layers, making every other layer down the chain corrupted as a key and a functional piece of code to make an entire program a pain in the ass to debug, as every step in the control flow would be relying on the rest of the layers to be in tact.

AND SO MUCH MORE :D


Go fourth and fuck shit up people lol



also, this lol

2:27 AM <MadMouse> also, in theory, you could overlap the key into the encrypted code
2:27 AM <Turn> Yea
2:27 AM <MadMouse> making its decryption dependent on the integrity of the first bit as well
2:28 AM <MadMouse> i just didnt want to calculate all that byte code by hand
2:28 AM <MadMouse> it would have required a FAR more manual apprah lol
2:28 AM <MadMouse> and stratyegic planning
2:28 AM <MadMouse> strategic*
2:28 AM <MadMouse> far more manual approach*



BTW, here is a little preview of what happens when a break point offsets the code key in memory:

When things run smoothly, and no corruption has occurred
Image

When a breakpoint offsets the key:
Image

I also forgot to meantion that the encrypted code completely destroys a disassemblers ability to accurately disassemble all code that follows the encrypted code, and will also completely destroy your ability to do dead code analysis without custom scripting :D
const char main[]="\xeb\xfe -> A fully functional program in C";

<@MadMouse> i am forgot what i was doing today but i had motivation and a distinct plan when i woke up stoned right now

http://pastebin.com/FnwUG5KS
Books:
http://goo.gl/muPm3d
User avatar
MadM0use
Experienced User
Experienced User
 
Posts: 70
Joined: Thu Sep 11, 2014 10:30 pm
Blog: View Blog (0)


Return to Custom Code

Who is online

Users browsing this forum: No registered users and 0 guests