Transcript
Page 1: C++ and Assembly: Debugging and Reverse Engineering

C++ and Assembly: Debugging and Reverse EngineeringMike Gelfand

Page 2: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

About me

• Mike Gelfand

• Principal developer at SolarWinds MSP

• Used a handful of programming languages in the past 10+ years

• Love cats

Page 3: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Agenda

• What is the assembly language and how does it compare to C++?

• How do we leverage assembly knowledge in everyday life?

Page 4: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Assembly Language,whatever that is

Page 5: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Typical use in modern age

•Operating systems (bootloaders, hardware setup)•Compilers (intermediate language, inline assembler)•Performance-critical code (encryption, graphics, scientific simulations)•Reverse engineering•Debugging

Page 6: C++ and Assembly: Debugging and Reverse Engineering

leal -12(%ecx, %eax, 8), %edi

movzbl %ah, %ebp

fsub %st, %st(3)

(AT&T)

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Just how bad could it be?

CAN I HAZ CLARITY?!

Page 7: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Just how bad could it be?

leal -12(%ecx, %eax, 8), %edi

movzbl %ah, %ebp

fsub %st, %st(3)

(AT&T)

lea edi, [ecx + eax * 8 - 12]

movzx ebp, ah

fsub st(3), st

(Intel)

Page 8: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Switching between Intel and AT&T flavors

Switch to Intel:

(gdb) set disassembly-flavor intel(lldb) settings set target.x86-disassembly-flavor intel

Switch to AT&T (but why?):

(gdb) set disassembly-flavor att(lldb) settings set target.x86-disassembly-flavor att

Page 9: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

x86 registers overview © Wikipedia

Page 10: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

General-purpose registers in the wild

Register Name Meaning [Extra] Use

RAX, EAX, AX Accumulator Result of multiplication or division

RBX, EBX, BX Base index Array index

RCX, ECX, CX Counter Number of iterations left in the loop or string operation

RDX, EDX, DX Data Multiplication result or dividend upper bits

RSP, ESP, SP Stack pointer Address of the top of the stack

RBP, EBP, BP Stack base pointer Address of the current stack frame

RSI, ESI, SI Source index Address of the current source operand of string operations

RDI, EDI, DI Destination index Address of the current destination operand of string operations

RIP, EIP Instruction pointer Address of the current instruction being executed

Page 11: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

C++ vs. Assembly: Basic stuff

C++

int a = 5;

a += 7;

int b = a - 4;

a |= b;

bool c = a & 7;

a *= b;

b = *(int*)(a + b);

Assembly (AT&T)

mov $5, %eax

add $7, %eax

lea -4(%eax), %ebx

or %ebx, %eax

test $7, %eax

imul %ebx

mov (%eax, %ebx), %ebx

Assembly (Intel)

mov eax, 5

add eax, 7

lea ebx, [eax - 4]

or eax, ebx

test eax, 7

imul ebx

mov ebx, [eax + ebx]

Page 12: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Flags register

Flag Meaning Category Use

CF Carry Status Carry or borrow indication (addition, subtraction, shift)

PF Parity Status Floating-point C2 flag check (e.g. FUCOM with NaN value)

AF Adjust Status Same as CF but just for the lower nibble (think BCD)

ZF Zero Status Result is zero/non-zero

SF Sign Status Result is negative/positive

OF Overflow Status Sign bit changed when adding two numbers of same sign, or subtracting two numbers of different signs

DF Direction Control Specifies string processing direction

Page 13: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

C++ vs. Assembly: Branching

C++

int a = 10;

while (a > 0)

{

if (a % 2 == 0)

a -= 3;

else

a /= 2;

}

Assembly (compiler)

[0x1f73] <+3>: mov ecx, 10

[0x1f76] <+6>: test ecx, ecx

[0x1f78] <+8>: jle 0x1f93 ; <+35>

[0x1f7a] <+10>: nop word ptr [eax + eax]

[0x1f80] <+16>: lea edx, [ecx - 0x3]

[0x1f83] <+19>: mov eax, ecx

[0x1f85] <+21>: shr eax

[0x1f87] <+23>: test cl, 0x1

[0x1f8a] <+26>: cmove eax, edx

[0x1f8d] <+29>: test eax, eax

[0x1f8f] <+31>: mov ecx, eax

[0x1f91] <+33>: jg 0x1f80 ; <+16>

[0x1f93] <+35>:

Assembly (human)

mov eax, 10

loop_start:

cmp eax, 0

jle finish

test eax, 1

jnz divide

sub eax, 3

jmp loop_start

divide:

sar eax, 1

jmp loop_start

finish:

Page 14: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Calling conventions

• Where parameters and results reside• In which order parameters are passed• Who cleans up after the call• What registers are preserved and who does it• etc.

Currently in wide use:• x86: cdecl, stdcall• x64: MS, System V

Page 15: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

C++ vs. Assembly: Calling functions (non-virtual, cdecl)

int f(int a, int b)

{

return a + b;

}

int g()

{

return f(2, 3) + 4;

}

f(int, int):

mov eax, DWORD PTR [esp + 0x8]

add eax, DWORD PTR [esp + 0x4]

ret

g():

push 0x3

push 0x2

call 0x8048520 <f(int, int)>

pop edx

add eax, 0x4

pop ecx

ret

Page 16: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

C++ vs. Assembly: Calling functions (virtual, cdecl)

struct I

{

virtual int f(int a, int b) = 0;

};

struct A : public I

{

int f(int a, int b) override

{

return a + b;

}

};

int g(I& x)

{

return x.f(2, 3) + 4;

}

A::f(int, int):

mov eax, DWORD PTR [esp + 0xc]

add eax, DWORD PTR [esp + 0x8]

ret

g(I&):

sub esp, 0x10

mov eax, DWORD PTR [esp + 0x14]

mov edx, DWORD PTR [eax]

push 0x3

push 0x2

push eax

call DWORD PTR [edx]

add esp, 0x1c

add eax, 0x4

ret

Page 17: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Assembly & DisassemberThe Rescue Rangers

Page 18: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #1: Waiting in kernel mode

// In a header far, far away

ULONG const TimeoutMs = 30000;

// Waiting up to 30 seconds for event to happen

LARGE_INTEGER timeout;

timeout.QuadPart = -1 * TimeoutMs * 10 * 1000;

NTSTATUS const waitResult =

KeWaitForSingleObject(&event, Executive,

KernelMode, FALSE, &timeout);

mov eax, dword ptr [TimeoutMs]

lea rcx, [rsp + 0x48] ; 1st arg

imul eax, eax, 0xFFFFD8F0

xor r9d, r9d ; 4th arg

xor r8d, r8d ; 3rd arg

xor edx, edx ; 2nd arg

mov qword ptr [rsp + 0x40], rax

lea rax, [rsp + 0x40]

mov qword ptr [rsp + 0x20], rax ; 5th arg

call qword ptr [_imp_KeWaitForSingleObject]

Page 19: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #1: Waiting in kernel mode

// In a header far, far away

LONG const TimeoutMs = 30000;

// Waiting up to 30 seconds for event to happen

LARGE_INTEGER timeout;

timeout.QuadPart = -1 * TimeoutMs * 10 * 1000;

NTSTATUS const waitResult =

KeWaitForSingleObject(&event, Executive,

KernelMode, FALSE, &timeout);

mov eax, dword ptr [TimeoutMs]

lea rcx, [rsp + 0x48] ; 1st arg

imul eax, eax, 0xFFFFD8F0

xor r9d, r9d ; 4th arg

xor r8d, r8d ; 3rd arg

xor edx, edx ; 2nd arg

cdqe

mov qword ptr [rsp + 0x40], rax

lea rax, [rsp + 0x40]

mov qword ptr [rsp + 0x20], rax ; 5th arg

call qword ptr [_imp_KeWaitForSingleObject]

Page 20: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #2: Magic statics

struct Data

{

int x;

Data() : x(123) {}

};

Data& GetData()

{

static Data data;

return data;

}

Page 21: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #2: Magic statics

GCC 4.2.1 (released 10 years ago)

0x08048560 <_Z7GetDatav+0>: push ebp

0x08048561 <_Z7GetDatav+1>: mov ebp,esp

0x08048563 <_Z7GetDatav+3>: sub esp,0x8

0x08048566 <_Z7GetDatav+6>: cmp BYTE PTR ds:0x8049790,0x0

0x0804856d <_Z7GetDatav+13>: je 0x8048576 <_Z7GetDatav+22>

0x0804856f <_Z7GetDatav+15>: leave

0x08048570 <_Z7GetDatav+16>: mov eax,0x8049798

0x08048575 <_Z7GetDatav+21>: ret

0x08048576 <_Z7GetDatav+22>: mov DWORD PTR [esp],0x8049790

0x0804857d <_Z7GetDatav+29>: call 0x80483e4 <__cxa_guard_acquire@plt>

0x08048582 <_Z7GetDatav+34>: test eax,eax

0x08048584 <_Z7GetDatav+36>: je 0x804856f <_Z7GetDatav+15>

0x08048586 <_Z7GetDatav+38>: mov DWORD PTR [esp],0x8049798

0x0804858d <_Z7GetDatav+45>: call 0x80485e0 <Data>

0x08048592 <_Z7GetDatav+50>: mov DWORD PTR [esp],0x8049790

0x08048599 <_Z7GetDatav+57>: call 0x8048414 <__cxa_guard_release@plt>

0x0804859e <_Z7GetDatav+62>: mov eax,0x8049798

0x080485a3 <_Z7GetDatav+67>: leave

0x080485a4 <_Z7GetDatav+68>: ret

Page 22: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #2: Magic statics

MSVC 12 (Visual Studio 2013)

example!GetData [example.cpp @ 14]:

14 00e61040 a14485e800 mov eax,dword ptr [example!$S1 (00e88544)]

15 00e61045 a801 test al,1

15 00e61047 7512 jne example!GetData+0x1b (00e6105b)

example!GetData+0x9 [example.cpp @ 15]:

15 00e61049 83c801 or eax,1

15 00e6104c b94085e800 mov ecx,offset example!data (00e88540)

15 00e61051 a34485e800 mov dword ptr [example!$S1 (00e88544)],eax

15 00e61056 e8aaffffff call example!ILT+0(??0DataQAEXZ) (00e61005)

example!GetData+0x1b [example.cpp @ 16]:

16 00e6105b b84085e800 mov eax,offset example!data (00e88540)

17 00e61060 c3 ret

Page 23: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #2: Magic statics

MSVC 15 (Visual Studio 2017)

example!GetData [example.cpp @ 14]:

14 010765a0 64a12c000000 mov eax,dword ptr fs:[0000002Ch]

15 010765a6 8b0d80fc0c01 mov ecx,dword ptr [example!_tls_index (010cfc80)]

15 010765ac 8b0c88 mov ecx,dword ptr [eax+ecx*4]

15 010765af a14cfc0c01 mov eax,dword ptr [example!type_info `RTTI Type Descriptor'+0x128 (010cfc4c)]

15 010765b4 3b8104010000 cmp eax,dword ptr [ecx+104h]

15 010765ba 7f06 jg example!GetData+0x22 (010765c2)

example!GetData+0x1c [example.cpp @ 16]:

16 010765bc b848fc0c01 mov eax,offset example!data (010cfc48)

17 010765c1 c3 ret

example!GetData+0x22 [example.cpp @ 15]:

15 010765c2 684cfc0c01 push offset example!type_info `RTTI Type Descriptor'+0x128 (010cfc4c)

15 010765c7 e8d9afffff call example!ILT+1440(__Init_thread_header) (010715a5)

15 010765cc 83c404 add esp,4

15 010765cf 833d4cfc0c01ff cmp dword ptr [example!type_info `RTTI Type Descriptor'+0x128 (010cfc4c)],0FFFFFFFFh

15 010765d6 75e4 jne example!GetData+0x1c (010765bc)

example!GetData+0x38 [example.cpp @ 15]:

15 010765d8 b948fc0c01 mov ecx,offset example!data (010cfc48)

15 010765dd e857c1ffff call example!ILT+5940(??0DataQAEXZ) (01072739)

15 010765e2 684cfc0c01 push offset example!type_info `RTTI Type Descriptor'+0x128 (010cfc4c)

15 010765e7 e89eb6ffff call example!ILT+3205(__Init_thread_footer) (01071c8a)

15 010765ec 83c404 add esp,4

15 010765ef ebcb jmp example!GetData+0x1c (010765bc)

Page 24: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #3: Code obfuscation

push edx

push 0x4920

mov dword ptr [esp], ecx

mov dword ptr [esp], edi

mov edi, 0x16BC2A97

push eax

mov eax, 0x7C4B60CD

add dword ptr [esp + 8], eax

mov eax, dword ptr [esp]

add esp, 4

add dword ptr [esp + 4], edi

sub dword ptr [esp + 4], 0x7C4B60CD

pop edi

push dword ptr [esp]

pop eax

push esi

mov esi, esp

add esi, 4

add esi, 4

xchg dword ptr [esp], esi

pop esp

push ebp

mov ebp, 0x16BC2A97

sub eax, ebp

pop ebp

mov edx, dword ptr [esp]

add esp, 4

void f(x86_regs32_t& regs, std::vector<std::uint32_t>& stack)

{

stack.push_back(regs.edx);

stack.push_back(0x4920);

stack[stack.size() - 1 - 0] = regs.ecx;

stack[stack.size() - 1 - 0] = regs.edi;

regs.edi = 0x16BC2A97;

stack.push_back(regs.eax);

regs.eax = 0x7C4B60CD;

stack[stack.size() - 1 - 2] += regs.eax;

regs.eax = stack[stack.size() - 1 - 0];

stack.pop_back();

stack[stack.size() - 1 - 1] += regs.edi;

stack[stack.size() - 1 - 1] -= 0x7C4B60CD;

regs.edi = stack[stack.size() - 1 - 0]; stack.pop_back();

stack.push_back(stack[stack.size() - 1 - 0]);

regs.eax = stack[stack.size() - 1 - 0]; stack.pop_back();

stack.push_back(regs.esi);

regs.esi = 0;

regs.esi += 1;

regs.esi += 1;

std::swap(stack[stack.size() - 1 - 0], regs.esi);

stack.resize(stack.size() - stack[stack.size() - 1 - 0] + 1);

stack.push_back(regs.ebp);

regs.ebp = 0x16BC2A97;

regs.eax -= regs.ebp;

regs.ebp = stack[stack.size() - 1 - 0]; stack.pop_back();

regs.edx = stack[stack.size() - 1 - 0];

stack.pop_back();

}

Page 25: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Example #3: Code obfuscation

mov eax, edx

add edx, 0x16BC2A97

void f(std::uint32_t& eax, std::uint32_t& edx)

{

regs.eax = regs.edx;

regs.edx += 0x16BC2A97;

}

Page 26: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

The Stuffin case you’re interested

Page 27: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Want to learn assembly and contribute at the same time?

• FASM — modern and fast assembler written in assemblyhttp://flatassembler.net/

• Menuet OS, Kolibri OS, BareMetal, and whole lot morehttp://wiki.osdev.org/Projects

• KOL & MCK by Vladimir Kladov (achtung: Delphi)http://kolmck.ru/

Page 28: C++ and Assembly: Debugging and Reverse Engineering

© 2017 SolarWinds MSP UK Ltd. All rights reserved.

Questions?

[email protected]@mikedld.com

Page 29: C++ and Assembly: Debugging and Reverse Engineering

The SolarWinds and SolarWinds MSP trademarks are the

exclusive property of SolarWinds MSP UK Ltd. or its affiliates

and may be registered or pending registration with the U.S.

Patent and Trademark Office and in other countries. All other

SolarWinds MSP UK and SolarWinds trademarks, service

marks, and logos may be common law marks or are registered

or pending registration. All other trademarks mentioned

herein are used for identification purposes only and are

trademarks (and may be registered trademarks) of their

respective companies.


Top Related