from unicorn import *
- ładujemy bibliotekę unicorna i stałe
from unicorn.x86_const import *
- ładujemy stałe dotyczące architektur x86 i x86_64
stałe występujące w module unicorn
:
UC_API_MAJOR UC_ERR_VERSION UC_MEM_READ UC_PROT_ALL
UC_API_MINOR UC_ERR_WRITE_PROT UC_MEM_READ_AFTER UC_PROT_EXEC
UC_ARCH_ARM UC_ERR_WRITE_UNALIGNED UC_MEM_READ_PROT UC_PROT_NONE
UC_ARCH_ARM64 UC_ERR_WRITE_UNMAPPED UC_MEM_READ_UNMAPPED UC_PROT_READ
UC_ARCH_M68K UC_HOOK_BLOCK UC_MEM_WRITE UC_PROT_WRITE
UC_ARCH_MAX UC_HOOK_CODE UC_MEM_WRITE_PROT UC_QUERY_MODE
UC_ARCH_MIPS UC_HOOK_INSN UC_MEM_WRITE_UNMAPPED UC_QUERY_PAGE_SIZE
UC_ARCH_PPC UC_HOOK_INTR UC_MILISECOND_SCALE UC_SECOND_SCALE
UC_ARCH_SPARC UC_HOOK_MEM_FETCH UC_MODE_16 UC_VERSION_EXTRA
UC_ARCH_X86 UC_HOOK_MEM_FETCH_INVALID UC_MODE_32 UC_VERSION_MAJOR
UC_ERR_ARCH UC_HOOK_MEM_FETCH_PROT UC_MODE_64 UC_VERSION_MINOR
UC_ERR_ARG UC_HOOK_MEM_FETCH_UNMAPPED UC_MODE_ARM Uc
UC_ERR_EXCEPTION UC_HOOK_MEM_INVALID UC_MODE_BIG_ENDIAN UcError
UC_ERR_FETCH_PROT UC_HOOK_MEM_PROT UC_MODE_LITTLE_ENDIAN arm64_const
UC_ERR_FETCH_UNALIGNED UC_HOOK_MEM_READ UC_MODE_MCLASS arm_const
UC_ERR_FETCH_UNMAPPED UC_HOOK_MEM_READ_AFTER UC_MODE_MICRO debug
UC_ERR_HANDLE UC_HOOK_MEM_READ_INVALID UC_MODE_MIPS3 m68k_const
UC_ERR_HOOK UC_HOOK_MEM_READ_PROT UC_MODE_MIPS32 mips_const
UC_ERR_HOOK_EXIST UC_HOOK_MEM_READ_UNMAPPED UC_MODE_MIPS32R6 sparc_const
UC_ERR_INSN_INVALID UC_HOOK_MEM_UNMAPPED UC_MODE_MIPS64 uc_arch_supported
UC_ERR_MAP UC_HOOK_MEM_VALID UC_MODE_PPC32 uc_version
UC_ERR_MODE UC_HOOK_MEM_WRITE UC_MODE_PPC64 unicorn
UC_ERR_NOMEM UC_HOOK_MEM_WRITE_INVALID UC_MODE_QPX unicorn_const
UC_ERR_OK UC_HOOK_MEM_WRITE_PROT UC_MODE_SPARC32 version_bind
UC_ERR_READ_PROT UC_HOOK_MEM_WRITE_UNMAPPED UC_MODE_SPARC64 x86_const
UC_ERR_READ_UNALIGNED UC_MEM_FETCH UC_MODE_THUMB
UC_ERR_READ_UNMAPPED UC_MEM_FETCH_PROT UC_MODE_V8
UC_ERR_RESOURCE UC_MEM_FETCH_UNMAPPED UC_MODE_V9
niektóre stałe występujące w module unicorn.x86_const
:
UC_X86_REG_EAX
UC_X86_REG_RIP
UC_X86_REG_RAX
mu = Uc(arch, mode)
np. mu = Uc(UC_ARCH_X86, UC_MODE_64)
- dostajemy instancję UE
mu.mem_map(ADDRESS, 4096)
- mapujemy pamięć
mu.mem_write(ADDRESS, DATA)
- zapisujemy do pamięci
tmp = mu.mem_read(ADDRESS, SIZE)
- odczytujemy z pamięci
mu.reg_write(UC_X86_REG_ECX, 0x0)
- ustawiamy rejestr na konkretną wartość. Tutaj konkretnie - ustawiamy rejestr ECX
na 0x0
r_esp = mu.reg_read(UC_X86_REG_ESP)
odczytujemy stan rejestru - tutaj konkretnie ESP
mu.emu_start(ADDRESS_START, ADDRESS_END)
- uruchamiamy kod
traking wykonywanych instrukcji:
def hook_code(uc, address, size, user_data):
print('>>> Tracing instruction at 0x%x, instruction size = 0x%x' %(address, size))
mu.hook_add(UC_HOOK_CODE, hook_code)
uc
- wskazuje na naszą instancjęaddress
- adres instrukcji która się wykonasize
- rozmiar instrukcji która się wykona
def read(name):
with open(name) as f:
return f.read()
def u32(data): #zamien ciag 4 bajtow na liczbe w formacie little-endian
return struct.unpack("I", data)[0]
def p32(num): #zamien liczbe w formacie little-endian na ciag 4 bajtow
return struct.pack("I", num)
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
void *v3; // rbp@1
int v4; // ebx@1
signed __int64 v5; // r8@2
char v6; // r9@3
__int64 v7; // r8@3
char v8; // cl@3
__int64 v9; // r9@5
int a2a; // [sp+Ch] [bp-1Ch]@3
v3 = &encrypted_flag;
v4 = 0;
setbuf(stdout, 0LL);
printf("The flag is: ", 0LL);
while ( 1 )
{
LODWORD(v5) = 0;
do
{
a2a = 0;
fibonacci(v4 + v5, &a2a);
v8 = v7;
v5 = v7 + 1;
}
while ( v5 != 8 );
v4 += 8;
if ( (unsigned __int8)(a2a << v8) == v6 )
break;
v3 = (char *)v3 + 1;
_IO_putc((char)(v6 ^ ((_BYTE)a2a << v8)), stdout);
v9 = *((char *)v3 - 1);
}
_IO_putc(10, stdout);
return 0LL;
}
unsigned int __fastcall fibonacci(int i, _DWORD *a2)
{
_DWORD *v2; // rbp@1
unsigned int v3; // er12@3
unsigned int result; // eax@3
unsigned int v5; // edx@3
unsigned int v6; // esi@3
unsigned int v7; // edx@4
v2 = a2;
if ( i )
{
if ( i == 1 )
{
result = fibonacci(0, a2);
v5 = result - ((result >> 1) & 0x55555555);
v6 = ((result - ((result >> 1) & 0x55555555)) >> 2) & 0x33333333;
}
else
{
v3 = fibonacci(i - 2, a2);
result = v3 + fibonacci(i - 1, a2);
v5 = result - ((result >> 1) & 0x55555555);
v6 = ((result - ((result >> 1) & 0x55555555)) >> 2) & 0x33333333;
}
v7 = v6 + (v5 & 0x33333333) + ((v6 + (v5 & 0x33333333)) >> 4);
*v2 ^= ((BYTE1(v7) & 0xF) + (v7 & 0xF) + (unsigned __int8)((((v7 >> 8) & 0xF0F0F) + (v7 & 0xF0F0F0F)) >> 16)) & 1;
}
else
{
*a2 ^= 1u;
result = 1;
}
return result;
}
funkcja main
:
.text:00000000004004E0 main proc near ; DATA XREF: start+1D�o
.text:00000000004004E0
.text:00000000004004E0 var_1C = dword ptr -1Ch
.text:00000000004004E0
.text:00000000004004E0 push rbp
.text:00000000004004E1 push rbx
.text:00000000004004E2 xor esi, esi ; buf
.text:00000000004004E4 mov ebp, offset unk_4007E1
.text:00000000004004E9 xor ebx, ebx
.text:00000000004004EB sub rsp, 18h
.text:00000000004004EF mov rdi, cs:stdout ; stream
.text:00000000004004F6 call _setbuf
.text:00000000004004FB mov edi, offset format ; "The flag is: "
.text:0000000000400500 xor eax, eax
.text:0000000000400502 call _printf
.text:0000000000400507 mov r9d, 49h
.text:000000000040050D nop dword ptr [rax]
.text:0000000000400510
.text:0000000000400510 loc_400510: ; CODE XREF: main+8A�j
.text:0000000000400510 xor r8d, r8d
.text:0000000000400513 jmp short loc_40051B
.text:0000000000400513 ; ---------------------------------------------------------------------------
.text:0000000000400515 align 8
.text:0000000000400518
.text:0000000000400518 loc_400518: ; CODE XREF: main+67�j
.text:0000000000400518 mov r9d, edi
.text:000000000040051B
.text:000000000040051B loc_40051B: ; CODE XREF: main+33�j
.text:000000000040051B lea edi, [rbx+r8]
.text:000000000040051F lea rsi, [rsp+28h+var_1C]
.text:0000000000400524 mov [rsp+28h+var_1C], 0
.text:000000000040052C call fibonacci
.text:0000000000400531 mov edi, [rsp+28h+var_1C]
.text:0000000000400535 mov ecx, r8d
.text:0000000000400538 add r8, 1
.text:000000000040053C shl edi, cl
.text:000000000040053E mov eax, edi
.text:0000000000400540 xor edi, r9d
.text:0000000000400543 cmp r8, 8
.text:0000000000400547 jnz short loc_400518
.text:0000000000400549 add ebx, 8
.text:000000000040054C cmp al, r9b
.text:000000000040054F mov rsi, cs:stdout ; fp
.text:0000000000400556 jz short loc_400570
.text:0000000000400558 movsx edi, dil ; c
.text:000000000040055C add rbp, 1
.text:0000000000400560 call __IO_putc
.text:0000000000400565 movzx r9d, byte ptr [rbp-1]
.text:000000000040056A jmp short loc_400510
.text:000000000040056A ; ---------------------------------------------------------------------------
.text:000000000040056C align 10h
.text:0000000000400570
.text:0000000000400570 loc_400570: ; CODE XREF: main+76�j
.text:0000000000400570 mov edi, 0Ah ; c
.text:0000000000400575 call __IO_putc
.text:000000000040057A add rsp, 18h
.text:000000000040057E xor eax, eax
.text:0000000000400580 pop rbx
.text:0000000000400581 pop rbp
.text:0000000000400582 retn
.text:0000000000400582 main endp
funkcja fibonacci
:
.text:0000000000400670 fibonacci proc near ; CODE XREF: main+4C�p
.text:0000000000400670 ; fibonacci+19�p ...
.text:0000000000400670 test edi, edi
.text:0000000000400672 push r12
.text:0000000000400674 push rbp
.text:0000000000400675 mov rbp, rsi
.text:0000000000400678 push rbx
.text:0000000000400679 jz short loc_4006F8
.text:000000000040067B cmp edi, 1
.text:000000000040067E mov ebx, edi
.text:0000000000400680 jz loc_400710
.text:0000000000400686 lea edi, [rdi-2]
.text:0000000000400689 call fibonacci
.text:000000000040068E lea edi, [rbx-1]
.text:0000000000400691 mov r12d, eax
.text:0000000000400694 mov rsi, rbp
.text:0000000000400697 call fibonacci
.text:000000000040069C add eax, r12d
.text:000000000040069F mov edx, eax
.text:00000000004006A1 mov ebx, eax
.text:00000000004006A3 shr edx, 1
.text:00000000004006A5 and edx, 55555555h
.text:00000000004006AB sub ebx, edx
.text:00000000004006AD mov ecx, ebx
.text:00000000004006AF mov edx, ebx
.text:00000000004006B1 shr ecx, 2
.text:00000000004006B4 and ecx, 33333333h
.text:00000000004006BA mov esi, ecx
.text:00000000004006BC
.text:00000000004006BC loc_4006BC: ; CODE XREF: fibonacci+C2�j
.text:00000000004006BC and edx, 33333333h
.text:00000000004006C2 lea ecx, [rsi+rdx]
.text:00000000004006C5 mov edx, ecx
.text:00000000004006C7 shr edx, 4
.text:00000000004006CA add edx, ecx
.text:00000000004006CC mov esi, edx
.text:00000000004006CE and edx, 0F0F0F0Fh
.text:00000000004006D4 shr esi, 8
.text:00000000004006D7 and esi, 0F0F0Fh
.text:00000000004006DD lea ecx, [rsi+rdx]
.text:00000000004006E0 mov edx, ecx
.text:00000000004006E2 shr edx, 10h
.text:00000000004006E5 add edx, ecx
.text:00000000004006E7 and edx, 1
.text:00000000004006EA xor [rbp+0], edx
.text:00000000004006ED pop rbx
.text:00000000004006EE pop rbp
.text:00000000004006EF pop r12
.text:00000000004006F1 retn
.text:00000000004006F1 ; ---------------------------------------------------------------------------
.text:00000000004006F2 align 8
.text:00000000004006F8
.text:00000000004006F8 loc_4006F8: ; CODE XREF: fibonacci+9�j
.text:00000000004006F8 mov edx, 1
.text:00000000004006FD xor [rbp+0], edx
.text:0000000000400700 mov eax, 1
.text:0000000000400705 pop rbx
.text:0000000000400706 pop rbp
.text:0000000000400707 pop r12
.text:0000000000400709 retn
.text:0000000000400709 ; ---------------------------------------------------------------------------
.text:000000000040070A align 10h
.text:0000000000400710
.text:0000000000400710 loc_400710: ; CODE XREF: fibonacci+10�j
.text:0000000000400710 xor edi, edi
.text:0000000000400712 call fibonacci
.text:0000000000400717 mov edx, eax
.text:0000000000400719 mov edi, eax
.text:000000000040071B shr edx, 1
.text:000000000040071D and edx, 55555555h
.text:0000000000400723 sub edi, edx
.text:0000000000400725 mov esi, edi
.text:0000000000400727 mov edx, edi
.text:0000000000400729 shr esi, 2
.text:000000000040072C and esi, 33333333h
.text:0000000000400732 jmp short loc_4006BC
.text:0000000000400732 fibonacci endp
adres 0x0000000000400670
w pamięci virtualnej ma offset 0x670
w pliku. czyli base = 0x0000000000400000
przenalizuj ten zobfuskowany shellcode za pomocą UE:
\x31\xd2\x52\xb8\xb7\xd8\x3e\x56\x05\x78\x56\x34\x12\x50\xb8\xde\xc0\xad\xde\x2d\xaf\x5e\x44\x70\x50\x6a\x0b\x58\x89\xd1\x89\xe3\x6a\x01\x5e\xcd\x80\x96\xcd\x80
tym razem architektura to x86_32
a@agnieszkab ~/ $ disasm 31d252b8b7d83e56057856341250b8dec0adde2daf5e4470506a0b5889d189e36a015ecd8096cd80
0: 31 d2 xor edx, edx
2: 52 push edx
3: b8 b7 d8 3e 56 mov eax, 0x563ed8b7
8: 05 78 56 34 12 add eax, 0x12345678
d: 50 push eax
e: b8 de c0 ad de mov eax, 0xdeadc0de
13: 2d af 5e 44 70 sub eax, 0x70445eaf
18: 50 push eax
19: 6a 0b push 0xb
1b: 58 pop eax
1c: 89 d1 mov ecx, edx
1e: 89 e3 mov ebx, esp
20: 6a 01 push 0x1
22: 5e pop esi
23: cd 80 int 0x80
25: 96 xchg esi, eax
26: cd 80 int 0x80
podpowiedź: instrukcja int 0x80
to bajty 0xcd 0x80
. Można zrobić na te bajty hooka i odczytać odpowiednie rejestry. rejestr EAX
przechowuje numer syscalla. lista syscalli. Argumenty syscalla są przechowywane kolejno w rejestrach EBX
, ECX
, EDX
, ESI
, EDI
.
int strcmp(char *a, char *b)
{
//get length
int len = 0;
char *ptr = a;
while(*ptr)
{
ptr++;
len++;
}
//comparestrings
for(int i=0; i<=len; i++)
{
if (a[i]!=b[i])
return 1;
}
return 0;
}
__attribute__((stdcall))
int super_function(int a, char *b)
{
if (a==5 && !strcmp(b, "zegnam"))
{
return 1;
}
return 0;
}
int main()
{
super_function(1, "witam");
}
wywołaj funkcje super_function
tak, aby zwróciła wartość 1
. Program jest 32 bitowy
asm:
.text:08048464 super_function proc near ; CODE XREF: main+16�p
.text:08048464
.text:08048464 arg_0 = dword ptr 8
.text:08048464 arg_4 = dword ptr 0Ch
.text:08048464
.text:08048464 push ebp
.text:08048465 mov ebp, esp
.text:08048467 call __x86_get_pc_thunk_ax
.text:0804846C add eax, 1B94h
.text:08048471 cmp [ebp+arg_0], 5
.text:08048475 jnz short loc_8048494
.text:08048477 lea eax, (aZegnam - 804A000h)[eax] ; "zegnam"
.text:0804847D push eax
.text:0804847E push [ebp+arg_4]
.text:08048481 call strcmp
.text:08048486 add esp, 8
.text:08048489 test eax, eax
.text:0804848B jnz short loc_8048494
.text:0804848D mov eax, 1
.text:08048492 jmp short locret_8048499
.text:08048494 ; ---------------------------------------------------------------------------
.text:08048494
.text:08048494 loc_8048494: ; CODE XREF: super_function+11�j
.text:08048494 ; super_function+27�j
.text:08048494 mov eax, 0
.text:08048499
.text:08048499 locret_8048499: ; CODE XREF: super_function+2E�j
.text:08048499 leave
.text:0804849A retn 8
.text:0804849A super_function endp
adres 0x08048464
w pamięci virtualnej będzie miał offset w pliku 0x464
. Czyli base = 0x08048000
Szczątkowe rozwiązania (prawdopodobnie WIP):