Slides
Slides
Workshop
Singapore – December, 3rd 2022
Introduction
Workshop Presentation
• Driven by hands-on.
1
VM
• Ubuntu 22.04
• Login: re / Password: re
• Ghidra 10.2
2
About
• Security Engineer
Open Obfuscator
3
Practical Reverse Engineering
Reverse Engineering
4
Reverse Engineering
Functionalities:
• An algorithm.
5
Reverse Engineering
Functionalities:
• An algorithm.
• A check.
5
Reverse Engineering
Functionalities:
• An algorithm.
• A check.
• A structure.
5
Reverse Engineering
Assets:
• Password.
6
Reverse Engineering
Assets:
• Password.
• An API Key.
6
Reverse Engineering
Original information:
7
Reverse Engineering
Original information:
7
Reverse Engineering
Original information:
7
Reverse Engineering
source.cpp executable.bin
object.o library.so
source.cpp
8
Reverse Engineering
source.cpp executable.bin
object.o library.so
source.cpp
9
Linux x86-64 Reverse Engineering
10
Linux x86-64 Reverse Engineering
• Vocabulary
11
Linux x86-64 Reverse Engineering
• Vocabulary • Instructions
11
Linux x86-64 Reverse Engineering
• Vocabulary • Instructions
• Grammar
11
Linux x86-64 Reverse Engineering
• Vocabulary • Instructions
11
Linux x86-64 Reverse Engineering
• Vocabulary • Instructions
• Idioms/Expressions
11
Linux x86-64 Reverse Engineering
• Vocabulary • Instructions
11
Linux x86-64 Reverse Engineering
push r12
push rbp
push rbx
mov rbx, rdi
mov rdi, rsi
sub rsp, 60h
mov r12, [rbx+28h]
mov rax, fs:28h
mov [rsp+78h�var_20], rax
xor eax, eax
movzx esi, byte ptr [r12+10h]
movss xmm0, dword ptr [r12+8]
call sub_16C90
test rax, rax
jz loc_B0CD
mov rbp, rax
cmp [rbx+10h], rax
jz loc_B114
12
Linux x86-64 Reverse Engineering
push r12
push rbp
push rbx Prologue
mov rbx, rdi
mov rdi, rsi
sub rsp, 60h
mov r12, [rbx+28h]
mov rax, fs:28h Stack Cookies
mov [rsp+78h�var_20], rax
xor eax, eax Compiler Optimization
movzx esi, byte ptr [r12+10h]
movss xmm0, dword ptr [r12+8]
call sub_16C90
test rax, rax Registers
jz loc_B0CD
mov rbp, rax
cmp [rbx+10h], rax
jz loc_B114
Instructions
13
x86-64: Registers
push r12
push rbp
push rbx rax eax ah al
mov rbx, rdi
mov rdi, rsi 64 Bits
32 Bits
14
x86-64: Registers
push r12
push rbp
push rbx rax eax ah al
mov rbx, rdi
mov rdi, rsi 64 Bits
32 Bits
15
x86-64: Registers
push r12
push rbp
push rbx rax eax ah al
mov rbx, rdi
mov rdi, rsi 64 Bits
32 Bits
push r12
push rbp
push rbx rax eax ah al
mov rbx, rdi
mov rdi, rsi 64 Bits
32 Bits
22
x86-64: Instructions
23
x86-64: Compiler Optimizations
24
x86-64: Compiler Optimizations
25
x86-64: Compiler Optimizations
26
x86-64: Compiler Optimizations
27
x86-64: Compiler Optimizations
28
x86-64: Compiler Optimizations
29
x86-64: Compiler Optimizations
30
x86-64: Compiler Optimizations
31
x86-64: Compiler Optimizations
32
x86-64: Compiler Optimizations
33
Calling Convention
34
x86-64: Calling Convention
1. The architecture
2. The operating system
35
x86-64: Calling Convention
36
x86-64: Calling Convention
int x = 1;
RDI
int y = 2;
RSI
int result = compute(x, y);
RDX
RCX
R8
R9
Other parameters are passed through the stack
mov dword ptr [rbp-0Ch], 1
call compute mov dword ptr [rbp-8], 2
mov edx, [rbp-8]
Return Value: RAX
mov eax, [rbp-0Ch]
mov esi, edx
mov edi, eax
call compute
mov [rbp-4], eax
37
x86-64: Prologue / Epilogue
38
x86-64: Prologue / Epilogue
push r15
"But compute() is not allowed to
push r14
modify the values of rbx, rbp, rdi, rsi, rsp, [...]"
push r13
Backup registers that are callee-saved push r12
push rbp
push rbx
mov rax, fs:28h
Initialize the stack cookie mov [rsp+0�88], rax
push rbx
push rbp
pop r12
Restore the callee-saved registers pop r13
pop r14
pop r15
39
x86-64: Endianness
uintptr_t* memory = ...;
�memory = 0�11223344;
44 33 22 11 00 00 00 00
mov rax, [rbp+var_8]
RAX = 0x113200E3AE324512
40
x86-64: Optimization
41
Linux Execution Bootstrapping
42
Linux Execution Bootstrapping
int main(int argc, char** argv) {
All executables must define a main()
printf("Hello World\n");
function which is the first function being
return 0;
executed when the executable starts.
}
43
Linux Execution Bootstrapping
$ readelf ��f�le�header compiled.bin
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI� UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable f�le)
int main(int argc, char** argv) {
Machine: Advanced Micro Devices X86-64 printf("Hello World\n");
Version: 0�1
Entry point address: 0�5eb0 return 0;
Start of program headers: 64 (bytes into f�le)
Start of section headers: 136080 (bytes into f�le) }
F�ags: 0�0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 26
Section header string table index: 25
44
Linux Execution Bootstrapping
$ readelf ��f�le�header compiled.bin
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI� UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable f�le)
int main(int argc, char** argv) {
Machine: Advanced Micro Devices X86-64 printf("Hello World\n");
Version: 0�1
Entry point address: 0�5eb0 return 0;
Start of program headers: 64 (bytes into f�le)
Start of section headers: 136080 (bytes into f�le) }
F�ags: 0�0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
int main(int argc, char** argv) {
Size of section headers: 64 (bytes)
Number of section headers: 26
printf("Hello World\n");
Section header string table index: 25 return 0;
}
��libc_start_main(&main, ...);
45
Linux Execution Bootstrapping
Cross-References
Cross-Ref
Entry Point
46
Linux Execution Bootstrapping
47
Demo
48
1 Hands-on #1: Simple Crackme
49
1
Level: Easy
$ ./crackme.elf foo
Missing login ��� Objectives: Getting started with reverse
engineering and compiler optimizations.
Try again!
$ ********** ./crackme.elf ****
Well done!
ELF x86-64
Involves Basic Mathematics Not Stripped
50
Hints
• http://flaviojslab.blogspot.com/2008/02/integer-division.html
• The charset of the password is abcdefghijklmnopqrstuvwxyz (lower case)
• What is the priority between xor and add ?
51
Reverse Engineering Structures
Reverse Engineering Structures
struct PointTy{
int x;
Reverse engineering is not always about
int y;
understanding a function or an algorithm. };
52
Reverse Engineering Structures
sub rsp, 18h
mov [rsp+18h+var_4], edi
mov [rsp+18h+var_8], esi
mov edi, 8
struct PointTy {
call _malloc
int x;
mov [rsp+18h+var_10], rax
mov eax, [rsp+18h+var_4]
int y;
mov rcx, [rsp+18h+var_10] };
mov [rcx], eax
mov eax, [rsp+18h+var_8] int compute(int x, int y) {
mov rcx, [rsp+18h+var_10] PointTy* P = malloc(sizeof(PointTy));
mov [rcx+4], eax P->x = x;
mov rax, [rsp+18h+var_10] P->y = y;
mov eax, [rax]
return P->x + P->y;
mov rcx, [rsp+18h+var_10]
}
add eax, [rcx+4]
add rsp, 18h
retn
53
Reverse Engineering Structures
Stack allocation
sub rsp, 18h
mov [rsp+18h+var_4], edi
mov [rsp+18h+var_8], esi
mov edi, 8 PointTy� P = malloc(sizeof(PointTy));
call _malloc
mov [rsp+18h+var_10], rax
mov eax, [rsp+18h+var_4]
mov rcx, [rsp+18h+var_10] P��x = x;
mov [rcx], eax
mov eax, [rsp+18h+var_8]
mov rcx, [rsp+18h+var_10] P��y = y;
mov [rcx+4], eax
mov rax, [rsp+18h+var_10]
mov eax, [rax]
mov rcx, [rsp+18h+var_10] return P��x + P��y;
add eax, [rcx+4]
add rsp, 18h
retn Stack deallocation
54
Reverse Engineering Structures
RAX
0
struct PointTy {
16
int x;
int y;
}; 24
32
40
55
Reverse Engineering Structures
RAX
0
struct PointTy {
16
void* x;
void* y;
}; 24
32
40
56
Reverse Engineering Structures
RAX
0
struct PointTy {
16
char x;
void* y;
}; 24
32
40
57
Reverse Engineering Structures
RAX
0
Padding
struct PointTy {
16
char x;
void* y;
}; 24
32
40
58
Reverse Engineering Structures
int compute(PointTy* P) {
P->x = 1;
P->y = 2;
return P->x + P->y;
}
int main(int argc, char** argv) {
PointTy P;
int value = compute(&P);
return value;
}
59
Reverse Engineering Structures
PUSH RBP
int compute(PointTy* P) { MOV RBP,RSP
P->x = 1; SUB RSP,0�20
MOV dword ptr [RBP + local_c],0�0
P->y = 2;
MOV dword ptr [RBP + local_10],EDI
return P->x + P->y;
MOV qword ptr [RBP + local_18],RSI
} LEA RDI=>local_20,[RBP + -0�18]
CALL FUN_00101120
int main(int argc, char** argv) { MOV dword ptr [RBP + local_24],EAX
PointTy P; MOV EAX,dword ptr [RBP + local_24]
int value = compute(&P); ADD RSP,0�20
return value; POP RBP
RET
}
60
Reverse Engineering Structures
�� main
int compute(PointTy* P) { undef�ned4 FUN_00101150(undef�ned4 param_1,���) {
P->x = 1; undef�ned4 uVar1;
P->y = 2; undef�ned local_20 [8];
undef�ned8 local_18;
return P->x + P->y; undef�ned4 local_10;
} undef�ned4 local_c;
local_c = 0;
int main(int argc, char** argv) {
local_18 = param_2;
PointTy P; local_10 = param_1;
int value = compute(&P); uVar1 = FUN_00101120(local_20);
return value; return uVar1;
}
}
61
Reverse Engineering Structures
int compute(PointTy* P) {
P->x = 1;
P->y = 2; PUSH RAX
return P->x + P->y;
MOV RDI,RSP
}
CALL FUN_00101120
int main(int argc, char** argv) { POP RCX
PointTy P; RET
int value = compute(&P);
return value;
}
62
Reverse Engineering Structures
int compute(PointTy* P) {
P->x = 1;
�� main
P->y = 2; void FUN_00101150(void) {
return P->x + P->y; undef�ned auStack_8[8];
}
int main(int argc, char** argv) { FUN_00101120(auStack_8);
PointTy P;
return;
int value = compute(&P);
return value; }
}
63
Reverse Engineering Structures
int compute(PointTy* P) {
P->x = 1;
P->y = 2;
return P->x + P->y;
}
int main(int argc, char** argv) {
PointTy P;
int value = compute(&P);
return value;
}
64
Reverse Engineering Structures
MOV qword ptr [RSP + local_8],RDI
int compute(PointTy* P) {
MOV RAX,qword ptr [RSP + local_8]
P->x = 1;
P->y = 2; MOV dword ptr [RAX],0�1
return P->x + P->y; MOV RAX,qword ptr [RSP + local_8]
} MOV dword ptr [RAX + 0�4],0�2
MOV RAX,qword ptr [RSP + local_8]
int main(int argc, char** argv) { MOV EAX,dword ptr [RAX]
PointTy P; MOV RCX,qword ptr [RSP + local_8]
int value = compute(&P); ADD EAX,dword ptr [RCX + 0�4]
return value;
RET
}
65
Reverse Engineering Structures
int compute(PointTy* P) {
P->x = 1; �� compute
P->y = 2; int FUN_00101120(int *param_1) {
return P->x + P->y;
}
*param_1 = 1;
param_1[1] = 2;
int main(int argc, char** argv) {
PointTy P; return *param_1 + param_1[1];
int value = compute(&P); }
return value;
}
66
Demo
67
2 Hands-on #2: Structures
68
2
Level: Medium
$ ./crackme_medium.elf 01020304
Try again! Objectives: Identify and reverse structures
$ ./crackme_medium.elf ********
Well done!
ELF x86-64
Involves Basic Arithmetic Operations Stripped
69
Reverse Engineering Large Binaries
Reverse Engineering Large Binaries
Most of the programs relies on third-party libraries that can be dynamically or statically
linked.
70
Reverse Engineering Large Binaries
MD5_Init(&ctx);
MD5_Update(&ctx, input, strlen(input));
MD5_Final(H, &ctx);
char H_str[MD5_DIGEST_LENGTH * 2];
for (size_t i = 0; i < MD5_DIGEST_LENGTH; ++i) {
sprintf(&H_str[i * 2], "%02x", H[i]);
}
printf("md5('%s')� %s\n", input, H_str);
}
71
Reverse Engineering Large Binaries
MD5_Init(&ctx);
MD5_Update(&ctx, input, strlen(input));
MD5_Final(H, &ctx); $ clang -O0 main.cpp �o main �lcrypto
char H_str[MD5_DIGEST_LENGTH * 2];
for (size_t i = 0; i < MD5_DIGEST_LENGTH; ++i) {
sprintf(&H_str[i * 2], "%02x", H[i]);
} Dynamic link with OpenSSL
printf("md5('%s')� %s\n", input, H_str);
}
72
Reverse Engineering Large Binaries
void FUN_001011a0(char *param_1) {
MD5 Computation with OpenSSL char *data;
size_t len;
void do_md5(const char* input) { ulong local_b0;
uint8_t H[MD5_DIGEST_LENGTH]; char local_a8 [32];
MD5_CTX local_88;
MD5_CTX ctx;
byte local_28 [24];
char *local_10;
MD5_Init(&ctx);
MD5_Update(&ctx, input, strlen(input)); local_10 = param_1;
MD5_Init(&local_88);
MD5_Final(H, &ctx); data = local_10;
len = strlen(local_10);
char H_str[MD5_DIGEST_LENGTH * 2]; MD5_Update(&local_88,data,len);
MD5_Final(local_28,&local_88);
for (size_t i = 0; i < MD5_DIGEST_LENGTH; ++i) {
for (local_b0 = 0; local_b0 < 0�10; local_b0 = local_b0 + 1) {
sprintf(&H_str[i * 2], "%02x", H[i]); sprintf(local_a8 + local_b0 * 2,"%02x",(ulong)local_28[local_b0]);
} }
printf("md5('%s')� %s\n", input, H_str); printf("md5(\'%s\')� %s\n",local_10,local_a8);
return;
}
73
Reverse Engineering Large Binaries
void FUN_001011a0(char *param_1) {
MD5 Computation with OpenSSL char *data;
size_t len;
void do_md5(const char* input) { ulong local_b0;
uint8_t H[MD5_DIGEST_LENGTH]; char local_a8 [32];
MD5_CTX local_88;
MD5_CTX ctx;
byte local_28 [24];
char *local_10;
MD5_Init(&ctx);
MD5_Update(&ctx, input, strlen(input)); local_10 = param_1;
MD5_Init(&local_88);
MD5_Final(H, &ctx); data = local_10;
len = strlen(local_10);
char H_str[MD5_DIGEST_LENGTH * 2]; MD5_Update(&local_88,data,len);
MD5_Final(local_28,&local_88);
for (size_t i = 0; i < MD5_DIGEST_LENGTH; ++i) {
for (local_b0 = 0; local_b0 < 0�10; local_b0 = local_b0 + 1) {
sprintf(&H_str[i * 2], "%02x", H[i]); sprintf(local_a8 + local_b0 * 2,"%02x",(ulong)local_28[local_b0]);
} }
printf("md5('%s')� %s\n", input, H_str); printf("md5(\'%s\')� %s\n",local_10,local_a8);
return;
}
Can't be stripped
74
Reverse Engineering Large Binaries
MD5_Init(&ctx);
MD5_Update(&ctx, input, strlen(input));
MD5_Final(H, &ctx); $ clang -O0 main.cpp �o main libcrypto.a
char H_str[MD5_DIGEST_LENGTH * 2];
for (size_t i = 0; i < MD5_DIGEST_LENGTH; ++i) {
sprintf(&H_str[i * 2], "%02x", H[i]);
} Static link with OpenSSL
printf("md5('%s')� %s\n", input, H_str);
}
75
Reverse Engineering Large Binaries
void FUN_0013d0f0(undef�ned8 param_1) {
undef�ned8 uVar1;
MD5 Computation with OpenSSL undef�ned8 uVar2;
ulong uStack_b0;
void do_md5(const char* input) { undef�ned auStack_a8 [32];
uint8_t H[MD5_DIGEST_LENGTH]; undef�ned auStack_88 [96];
undef�ned auStack_28 [24];
MD5_CTX ctx; undef�ned8 uStack_10;
MD5_Init(&ctx); uStack_10 = param_1;
FUN_0028ffa0(auStack_88);
MD5_Update(&ctx, input, strlen(input)); uVar1 = uStack_10;
MD5_Final(H, &ctx); uVar2 = strlen(uStack_10);
FUN_0028f940(auStack_88,uVar1,uVar2);
FUN_0028fb80(auStack_28,auStack_88);
char H_str[MD5_DIGEST_LENGTH * 2];
for (uStack_b0 = 0; uStack_b0 < 0�10; uStack_b0 = uStack_b0 + 1) {
for (size_t i = 0; i < MD5_DIGEST_LENGTH; ++i) { sprintf(auStack_a8 + uStack_b0 * 2,&DAT_003a1ed1,auStack_28[uStack_b0]);
sprintf(&H_str[i * 2], "%02x", H[i]); }
printf(&DAT_00363004,uStack_10,auStack_a8);
}
return;
printf("md5('%s')� %s\n", input, H_str);
}
Statically imported functions
76
Reverse Engineering Large Binaries
local_10 = param_1; uStack_10 = param_1;
MD5_Init(&local_88); FUN_0028ffa0(auStack_88);
data = local_10; uVar1 = uStack_10;
len = strlen(local_10); uVar2 = strlen(uStack_10);
MD5_Update(&local_88,data,len); FUN_0028f940(auStack_88,uVar1,uVar2);
MD5_Final(local_28,&local_88); FUN_0028fb80(auStack_28,auStack_88);
for (local_b0 = 0; local_b0 < 0�10; local_b0 = local_b0 + 1) { for (uStack_b0 = 0; uStack_b0 < 0�10; uStack_b0 = uStack_b0 + 1) {
sprintf(local_a8 + local_b0 * 2,"%02x",(ulong)local_28[local_b0]); sprintf(auStack_a8 + uStack_b0 * 2,&DAT_003a1ed1,auStack_28[uStack_b0]);
} }
printf("md5(\'%s\')� %s\n",local_10,local_a8); printf(&DAT_00363004,uStack_10,auStack_a8);
return; return;
} }
77
Reverse Engineering Large Binaries
When a library is statically linked and the program correctly stripped1 , the reverse
engineering of the whole binary can be challenging.
78
Reverse Engineering Large Binaries
When a library is statically linked and the program correctly stripped1 , the reverse
engineering of the whole binary can be challenging.
⇒ We can quickly get lost while trying to analyse the binary.
78
Reverse Engineering Large Binaries
uStack_10 = param_1;
FUN_0028ffa0(auStack_88);
uVar1 = uStack_10;
uVar2 = strlen(uStack_10);
Easier to reverse
FUN_0028f940(auStack_88,uVar1,uVar2);
FUN_0028fb80(auStack_28,auStack_88);
for (uStack_b0 = 0; uStack_b0 < 0�10; uStack_b0 = uStack_b0 + 1) {
sprintf(auStack_a8 + uStack_b0 * 2,&DAT_003a1ed1,auStack_28[uStack_b0]);
}
printf(&DAT_00363004,uStack_10,auStack_a8);
return;
}
79
Reverse Engineering Large Binaries
Require that the user has the library with the correct version The library is embedded in the binary
80
Reverse Engineering Large Binaries
• Strings, logs
• Constants
81
1. Strings
82
Strings
83
Strings
assets/injectso_arm
84
Strings
assets/injectso_arm
85
Strings
86
Strings
87
2. Constants
88
Constants
void FUN_0013d0f0(undef�ned8 param_1) {
undef�ned8 uVar1;
undef�ned8 uVar2;
ulong uStack_b0;
undef�ned auStack_a8 [32];
undef�ned auStack_88 [96];
undef�ned auStack_28 [24];
undef�ned8 uStack_10;
uStack_10 = param_1;
FUN_0028ffa0(auStack_88);
uVar1 = uStack_10;
uVar2 = strlen(uStack_10);
FUN_0028f940(auStack_88,uVar1,uVar2);
FUN_0028fb80(auStack_28,auStack_88);
for (uStack_b0 = 0; uStack_b0 < 0�10; uStack_b0 = uStack_b0 + 1) {
sprintf(auStack_a8 + uStack_b0 * 2,&DAT_003a1ed1,auStack_28[uStack_b0]);
}
printf(&DAT_00363004,uStack_10,auStack_a8);
return;
89
Constants
void FUN_0013d0f0(undef�ned8 param_1) {
undef�ned8 uVar1;
undef�ned8 uVar2;
ulong uStack_b0;
undef�ned auStack_a8 [32];
undef�ned auStack_88 [96];
undef�ned auStack_28 [24];
undef�ned8 uStack_10;
uStack_10 = param_1;
FUN_0028ffa0(auStack_88);
uVar1 = uStack_10; MD5 Constants
uVar2 = strlen(uStack_10);
FUN_0028f940(auStack_88,uVar1,uVar2);
FUN_0028fb80(auStack_28,auStack_88);
for (uStack_b0 = 0; uStack_b0 < 0�10; uStack_b0 = uStack_b0 + 1) {
sprintf(auStack_a8 + uStack_b0 * 2,&DAT_003a1ed1,auStack_28[uStack_b0]);
}
printf(&DAT_00363004,uStack_10,auStack_a8);
return;
90
Constants
91
3. Relative Positioning
92
Constants
93
Relative Positioning
Likely MD5-related
functions
Likely MD5-related
functions
94
Relative Positioning
#include <stdio.h>
#include "md5_local.h"
#include <openssl/opensslv.h> MD5_Update(���)
��
* Implemented from RFC1321 The MD5 Message-Digest Algorithm
�� MD5_Transform(���)
#def�ne INIT_DATA_A (unsigned long)0�67452301L
#def�ne INIT_DATA_B (unsigned long)0�efcdab89L
#def�ne INIT_DATA_C (unsigned long)0�98badcfeL MD5_Final(���)
#def�ne INIT_DATA_D (unsigned long)0�10325476L
int MD5_Init(MD5_CTX *c)
{
memset(c, 0, sizeof(*c));
c->A = INIT_DATA_A;
c->B = INIT_DATA_B;
c->C = INIT_DATA_C;
c->D = INIT_DATA_D;
return 1;
}
OpenSSL_1_1_1s/crypto/md5/md5_dgst.c
95
Relative Positioning
#include <stdio.h>
#include "md5_local.h"
#include <openssl/opensslv.h> MD5_Update(���)
��
* Implemented from RFC1321 The MD5 Message-Digest Algorithm
�� MD5_Transform(���)
#def�ne INIT_DATA_A (unsigned long)0�67452301L
#def�ne INIT_DATA_B (unsigned long)0�efcdab89L
#def�ne INIT_DATA_C (unsigned long)0�98badcfeL MD5_Final(���)
#def�ne INIT_DATA_D (unsigned long)0�10325476L
int MD5_Init(MD5_CTX *c)
{
memset(c, 0, sizeof(*c)); $ readelf -SW ./md5_dgst.o
c->A = INIT_DATA_A; Section Headers:
c->B = INIT_DATA_B; [Nr] Name Type Off Size ES F�g Lk Inf Al
c->C = INIT_DATA_C; [ 3] .text.MD5_Update PROGBITS 000040 00020d 00 AX 0 0 16
c->D = INIT_DATA_D; [ 5] .text.MD5_Transform PROGBITS 000250 000028 00 AX 0 0 16
[ 7] .text.MD5_Final PROGBITS 000280 000417 00 AX 0 0 16
return 1;
[ 9] .text.MD5_Init PROGBITS 0006a0 000052 00 AX 0 0 16
}
OpenSSL_1_1_1s/crypto/md5/md5_dgst.c
96
Relative Positioning
Likely MD5-related
functions
Likely MD5-related
functions
97
Relative Positioning
Likely MD5-related
functions
98
Relative Positioning
$ readelf -SW ./md5_dgst.o
Section Headers:
[Nr] Name Type Off Size ES F�g Lk Inf Al
[ 3] .text.MD5_Update PROGBITS 000040 00020d 00 AX 0 0 16
[ 5] .text.MD5_Transform PROGBITS 000250 000028 00 AX 0 0 16
[ 7] .text.MD5_Final PROGBITS 000280 000417 00 AX 0 0 16
[ 9] .text.MD5_Init PROGBITS 0006a0 000052 00 AX 0 0 16
99
Relative Positioning
$ readelf -SW ./md5_dgst.o
Section Headers:
[Nr] Name Type Off Size ES F�g Lk Inf Al
[ 3] .text.MD5_Update PROGBITS 000040 00020d 00 AX 0 0 16
[ 5] .text.MD5_Transform PROGBITS 000250 000028 00 AX 0 0 16
[ 7] .text.MD5_Final PROGBITS 000280 000417 00 AX 0 0 16
[ 9] .text.MD5_Init PROGBITS 0006a0 000052 00 AX 0 0 16
MD5_Update
MD5_Transform
MD5_Final
100
Relative Positioning
As a rule of thumb:
Functions that are close each other in the source �le (or compilation unit),
are likely close in the compiled binary.
In particular, the relative order in the source code is preserved in the �nal
binary1.
1
This can be mitigated: https://github.com/open-obfuscator/o-mvll/blob/main/src/core/utils.cpp#L231-L257
101
3 Hands-on #3: Embedded Library
102
3
Level: Hard
$ ./crackme_hard.elf "azertyw"
Try again! Objectives: Reverse engineering a large binary with
$ ./crackme_hard.elf "***************" cryptography functions.
Well done!
ELF x86-64
Involves known cryptography algorithms Stripped
103
Guidelines
104
Closing Remarks
Closing Remarks
1. https://margin.re/2021/11/an-opinionated-guide-on-how-to-reverse-engineer-software-part-1/
2. https://margin.re/2021/11/an-opinionated-guide-on-how-to-reverse-engineer-software-part-2/
105
Closing Remarks
106
Closing Remarks
https://www.root-me.org
107
Thank You!
https://www.romainthomas.fr me@romainthomas.fr