Assume you have some unknown object file. The source code of it was
#include <stdio.h>
#include <string.h>
#define NCHAR 26
void setkey(int i);
char *encrypt(char *s);
char keybuf[NCHAR];
char codepoint(char c);
int main(void) {
char *secret;
setkey(5);
secret=strdup("Hello World");
printf("%s\n", encrypt(secret));
}
void setkey(int key) {
int i, val;
val=key;
for (i=0; i<NCHAR; i++) {
keybuf[i]=val%NCHAR;
val+=key;
}
}
char *encrypt(char *s) {
char *t=s;
while (*s) {
if (*s>='a' && *s<='z') {
*s='a'+codepoint(*s-'a');
} else if (*s>='A' && *s<='Z') {
*s='A'+codepoint(*s-'A');
}
s++;
}
return t;
}
char codepoint(char c) {
return keybuf[c];
}
The only thing you have is the object code. For reference, objdump -d original
yields
Disassembly of section .text:
0000000000400490 <_start>:
400490: 31 ed xor %ebp,%ebp
...
000000000040057d <main>:
40057d: 55 push %rbp
40057e: 48 89 e5 mov %rsp,%rbp
...
4005b2: c3 retq
00000000004005b3 <setkey>:
4005b3: 55 push %rbp
4005b4: 48 89 e5 mov %rsp,%rbp
...
4005ed: 48 98 cltq
4005ef: 88 90 60 10 60 00 mov %dl,0x601060(%rax)
4005f5: 8b 45 ec mov -0x14(%rbp),%eax
...
400606: c3 retq
0000000000400607 <encrypt>:
400607: 55 push %rbp
400608: 48 89 e5 mov %rsp,%rbp
...
400677: 89 c7 mov %eax,%edi
400679: e8 21 00 00 00 callq 40069f <codepoint>
40067e: 83 c0 41 add $0x41,%eax
...
40069e: c3 retq
000000000040069f <codepoint>:
40069f: 55 push %rbp
4006a0: 48 89 e5 mov %rsp,%rbp
...
4006ac: 48 98 cltq
4006ae: 0f b6 80 60 10 60 00 movzbl 0x601060(%rax),%eax
4006b5: 5d pop %rbp
4006b6: c3 retq
You want to use that code in your program.
To do this, you don't really have to understand or disassemble it, or make it compilable.
The only things you will need to find out, using IDA, a debugger, or your favourite tools, are:
- The interesting part of the code is the part from 0x4005B3 to 0x4006B6.
- This code references some variable at 0x601060 at two different locations, 0x4005ef and 0x4006ae. (The instructions need 2 resp. 3 bytes, so the addresses are at 0x4005b1 and 0x4006b1).
- To use it, you have to call the function at 0x4005b3 with an integer first, then the function at 0x400607 with a string to get the encrypted string.
Let's convert the whole .text section into an array of characters, ready to be embedded into C code:
$ objdump -s -j .text original | grep '^ 4' | cut -d' ' -f3-6 | tr -d ' ' | sed 's/../0x&,/g'
0x31,0xed,0x49,0x89,0xd1,0x5e,0x48,0x89,0xe2,0x48,0x83,0xe4,0xf0,0x50,0x54,0x49,
...
0x41,0x5e,0x41,0x5f,0xc3,0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,
0xf3,0xc3,
and write a new program to use it.
#include <stdio.h>
#include <string.h>
char code[]={
0x31,0xed,0x49,0x89,0xd1,0x5e,0x48,0x89,0xe2,0x48,0x83,0xe4,0xf0,0x50,0x54,0x49,
0xc7,0xc0,0x30,0x07,0x40,0x00,0x48,0xc7,0xc1,0xc0,0x06,0x40,0x00,0x48,0xc7,0xc7,
0x7d,0x05,0x40,0x00,0xe8,0xa7,0xff,0xff,0xff,0xf4,0x66,0x0f,0x1f,0x44,0x00,0x00,
0xb8,0x4f,0x10,0x60,0x00,0x55,0x48,0x2d,0x48,0x10,0x60,0x00,0x48,0x83,0xf8,0x0e,
0x48,0x89,0xe5,0x77,0x02,0x5d,0xc3,0xb8,0x00,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,
0xf4,0x5d,0xbf,0x48,0x10,0x60,0x00,0xff,0xe0,0x0f,0x1f,0x80,0x00,0x00,0x00,0x00,
0xb8,0x48,0x10,0x60,0x00,0x55,0x48,0x2d,0x48,0x10,0x60,0x00,0x48,0xc1,0xf8,0x03,
0x48,0x89,0xe5,0x48,0x89,0xc2,0x48,0xc1,0xea,0x3f,0x48,0x01,0xd0,0x48,0xd1,0xf8,
0x75,0x02,0x5d,0xc3,0xba,0x00,0x00,0x00,0x00,0x48,0x85,0xd2,0x74,0xf4,0x5d,0x48,
0x89,0xc6,0xbf,0x48,0x10,0x60,0x00,0xff,0xe2,0x0f,0x1f,0x80,0x00,0x00,0x00,0x00,
0x80,0x3d,0x19,0x0b,0x20,0x00,0x00,0x75,0x11,0x55,0x48,0x89,0xe5,0xe8,0x7e,0xff,
0xff,0xff,0x5d,0xc6,0x05,0x06,0x0b,0x20,0x00,0x01,0xf3,0xc3,0x0f,0x1f,0x40,0x00,
0x48,0x83,0x3d,0xc8,0x08,0x20,0x00,0x00,0x74,0x1e,0xb8,0x00,0x00,0x00,0x00,0x48,
0x85,0xc0,0x74,0x14,0x55,0xbf,0x20,0x0e,0x60,0x00,0x48,0x89,0xe5,0xff,0xd0,0x5d,
0xe9,0x7b,0xff,0xff,0xff,0x0f,0x1f,0x00,0xe9,0x73,0xff,0xff,0xff,0x55,0x48,0x89,
0xe5,0x48,0x83,0xec,0x10,0xbf,0x05,0x00,0x00,0x00,0xe8,0x24,0x00,0x00,0x00,0xbf,
0x44,0x07,0x40,0x00,0xe8,0xe7,0xfe,0xff,0xff,0x48,0x89,0x45,0xf8,0x48,0x8b,0x45,
0xf8,0x48,0x89,0xc7,0xe8,0x5e,0x00,0x00,0x00,0x48,0x89,0xc7,0xe8,0x9f,0xfe,0xff,
0xff,0xc9,0xc3,0x55,0x48,0x89,0xe5,0x89,0x7d,0xec,0x8b,0x45,0xec,0x89,0x45,0xfc,
0xc7,0x45,0xf8,0x00,0x00,0x00,0x00,0xeb,0x36,0x8b,0x4d,0xfc,0xba,0x4f,0xec,0xc4,
0x4e,0x89,0xc8,0xf7,0xea,0xc1,0xfa,0x03,0x89,0xc8,0xc1,0xf8,0x1f,0x29,0xc2,0x89,
0xd0,0x6b,0xc0,0x1a,0x29,0xc1,0x89,0xc8,0x89,0xc2,0x8b,0x45,0xf8,0x48,0x98,0x88,
0x90,0x60,0x10,0x60,0x00,0x8b,0x45,0xec,0x01,0x45,0xfc,0x83,0x45,0xf8,0x01,0x83,
0x7d,0xf8,0x19,0x7e,0xc4,0x5d,0xc3,0x55,0x48,0x89,0xe5,0x48,0x83,0xec,0x20,0x48,
0x89,0x7d,0xe8,0x48,0x8b,0x45,0xe8,0x48,0x89,0x45,0xf8,0xeb,0x71,0x48,0x8b,0x45,
0xe8,0x0f,0xb6,0x00,0x3c,0x60,0x7e,0x2c,0x48,0x8b,0x45,0xe8,0x0f,0xb6,0x00,0x3c,
0x7a,0x7f,0x21,0x48,0x8b,0x45,0xe8,0x0f,0xb6,0x00,0x83,0xe8,0x61,0x0f,0xbe,0xc0,
0x89,0xc7,0xe8,0x58,0x00,0x00,0x00,0x83,0xc0,0x61,0x89,0xc2,0x48,0x8b,0x45,0xe8,
0x88,0x10,0xeb,0x35,0x48,0x8b,0x45,0xe8,0x0f,0xb6,0x00,0x3c,0x40,0x7e,0x2a,0x48,
0x8b,0x45,0xe8,0x0f,0xb6,0x00,0x3c,0x5a,0x7f,0x1f,0x48,0x8b,0x45,0xe8,0x0f,0xb6,
0x00,0x83,0xe8,0x41,0x0f,0xbe,0xc0,0x89,0xc7,0xe8,0x21,0x00,0x00,0x00,0x83,0xc0,
0x41,0x89,0xc2,0x48,0x8b,0x45,0xe8,0x88,0x10,0x48,0x83,0x45,0xe8,0x01,0x48,0x8b,
0x45,0xe8,0x0f,0xb6,0x00,0x84,0xc0,0x75,0x84,0x48,0x8b,0x45,0xf8,0xc9,0xc3,0x55,
0x48,0x89,0xe5,0x89,0xf8,0x88,0x45,0xfc,0x0f,0xbe,0x45,0xfc,0x48,0x98,0x0f,0xb6,
0x80,0x60,0x10,0x60,0x00,0x5d,0xc3,0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,
0x41,0x57,0x41,0x89,0xff,0x41,0x56,0x49,0x89,0xf6,0x41,0x55,0x49,0x89,0xd5,0x41,
0x54,0x4c,0x8d,0x25,0x38,0x07,0x20,0x00,0x55,0x48,0x8d,0x2d,0x38,0x07,0x20,0x00,
0x53,0x4c,0x29,0xe5,0x31,0xdb,0x48,0xc1,0xfd,0x03,0x48,0x83,0xec,0x08,0xe8,0x25,
0xfd,0xff,0xff,0x48,0x85,0xed,0x74,0x1e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,
0x4c,0x89,0xea,0x4c,0x89,0xf6,0x44,0x89,0xff,0x41,0xff,0x14,0xdc,0x48,0x83,0xc3,
0x01,0x48,0x39,0xeb,0x75,0xea,0x48,0x83,0xc4,0x08,0x5b,0x5d,0x41,0x5c,0x41,0x5d,
0x41,0x5e,0x41,0x5f,0xc3,0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00,
0xf3,0xc3,
};
// we don't know how large it has to be. From the disassembly,
// we learned 26 bytes should be enough. Better make it larger and be
// on the safe side.
char buffer[1000];
int main(void) {
void (*f1)(int)=(void *)(code-0x400490+0x4005b3);
char* (*f2)(char *)=(void *)(code-0x400490+0x400607);
*(int *)(code-0x400490+0x4005f1)=(int)(long)&buffer;
*(int *)(code-0x400490+0x4006b1)=(int)(long)&buffer;
(*f1)(5);
printf("%s\n", (*f2)(strdup("Hello World")));
printf("%s\n", (*f2)(strdup("Some other String")));
}
Since the original text segment started at 0x400490, and our functions started at 0x4005b3 and 0x400607, we calculate the new offsets from the start of the code
array. And since we
found two references to a buffer outside the original program, we patch them to point to our buffer instead. Note we don't have to do anything with the call from encrypt to codepoint,
since the code is position-independent anyway (call the function at 0x21 bytes from here).
Now, don't forget to make the data/stack segment executable when we compile the program:
$ cc -zexecstack -g -o copy copy.c
$ ./copy
Oziix Lxmiu
Rxnz xwozm Rwmtsj
Of course, there's still some problems to solve:
- You have to find everything that might get called from your functions, and include all of it into your code.
- You have to find all references to data outside your code, and patch the pointers accordingly; if the data contains pointers, patch them as well.
- If your code calls any library functions, you'll have to do the relocation. Fortunately, the relocation table of the (ELF/PE) binary shows you where to do this.
The upside of this approach is it can even work between operating systems, if they use the same processor architecture. You might need to write wrapper functions around the calls however,
if the ABI is different.
If you want to get fancy, don't call the functions directly; embed an emulator engine in your program and have the emulator execute the code. This can help you a lot to detect if
some code is missing, or where references to external data are. Once you get it running with an emulator, obviously, you can leave it in your final program, which may even enable
you to use some ARM routines in your new PC program. Or vice versa.
You can download the files at
https://mega.co.nz/#!8dR0TZhA!Z4DdQ07JCUzV5nJiJ79PZhHbiKDu9QZEw10IXr7ssuI