3. 소스코드를 역추적하는 것
개발자가 코딩을 완료하고 빌드를 하게 되면 소스코드를 컴파일과정을 거
쳐 오브젝트 파일이 만들어지며, 여러 링크된 라이브러리와 오브젝트 파일
을 결합해 최종적으로 EXE DLL등이 생성된다.
빌드된 EXE, DLL등을 바이너리 분석을 거쳐서 소스코드가 어떤 식으로
만들어져 있는지 파악이 가능해진다. PE Header 분석을 통해 어떤 라이브
러리가 링크돼 있는지 분석하고, 버튼을 눌렀을 때 가동되는 코드의 흐름을
추적해 원래의 코드가 어떤 식으로 제작돼 있는지 알 수 있게 된다.
4. • 소스코드의 구조를 분석해서 코드변조를 통해 허가되지 않은 액
션이 가능한지등 취약점 발견
모의해킹 취약점 발견
• 해커의 침입 여부를 역분석해서 그에 상응하는 보안 모듈 개발보안코드 개발
• 코드상에선 문제가 없지만 다른 모듈이 결합했을 때 등, 예상치 못
한 상황에서 예외가 발생했을 때 등에 대해 원인 파악 가능
버그 수정
• 새로운 프로그램이 등장했는데, 구글링해도 나오지 않을 때, 리버
싱하면 기술에 대한 궁금증을 해결
신기술 연구와 학습
6. Void 물마심()
{
BOOL bOpen = 냉장고문오픈();
if (bOpen)
{
물을꺼냄();
마심();
}
}
__asm{
냉장고앞으로간다
냉장고문을잡는다
냉장고문을연다
오픈성공:
냉장고안을본다
손을든다
냉장고안에넣는다
물병을잡는다
물병을꺼낸다
뚜껑을연다
물을컵에따른다
컵을손에든다
컵에든것을마신다.
C/C++ 코드와의 결정적인 차이
: “한 번에 한 가지 동작”
[어셈블리는 간단명료하다]
기본 구조(feat. 물마심)
7. 명령 포맷
• X86 CPU의 기본 구조인 IA-32를 기본 플랫폼으로 삼아 소개함
대부분의 PC가 Intel CPU를 사용하며, AMD의 경우도 대부분의 코드가 Intel
Processor와 호환되기 때문이다.
• “명령어 + 인자”
IA-32의 기본 형태
명령어 mov, push 같은 것들. 옵코드(opcode)
인자: “어떤 장소로 값을 넣을 것인지”, “명령어에 해당하는 값.” 오퍼랜드(operand)
• Push 337
Push는 옵코드, 337는 오퍼랜드
• Mov eax, 1
Mov는 옵코드, eax와 1이 오퍼랜드
모든 오퍼랜드는 앞의 것이 destination 뒤의 것이 source
9. EAX
산술 계산을 하며, 리턴 값을 전달하는 변수.
A = Accumulator
EDX
각종 연산에 쓰이나,
리턴 값에 쓰이지 않는 변수
D = Data
ECX
C = Count
For 문에서 int I 라고 선언할 때의 i의 역할
카운팅 할 필요 없을 때는 그저 변수.
EBX
레지스터가 하나 더
필요할 때 사용되는 것.
10. • ESI (Source Index)
시작지 인덱스
데이터를 조작하거나, 복사 시에 데이
터의 주소가 저장되는 변수
• EDI (Destination Index)
목적지 인덱스
복사 시에 목적지의 주소가 저장되는
변수
• EBP(Stack Pointer)
스택 프레임의 끝 지점 주소가 저장됨.
• ESP(Baste Pointer)
스택프레임의 시작 주소가 저장됨.
11. 기본적인명령어
• ADD, SUB
ADD : Src에서 dest로 값을 더하는 명령어
SUB : Src에서 dest로 값을 빼는 명령어
• INT
인터럽트를 일으키는 명령어
• CALL
함수를 호출하는 명령어
CALL뒤에 오퍼랜드로 번지가 붙는다. 해당
번지를 호출하고 끝나면 call다음 번지로 돌
아온다.
• INC, DEC
INC = i++; DEC = i--;
• PUSH, POP
PUSH : 스택에 값을 넣는 명령어
POP : 스택에 있는 값을 가져오는 명령어
• MOV
값을 넣는 명령어
Mov eax, 1 : eax에 1을 넣는 코드
Mov ebx, ecx : ebx에 ecx를 넣는 코드
• LEA
주소를 넣는 것
Lea eax, dword ptr ds:[esi] : eax에 0x401000
Mov eax, dword ptr ds:[esi] : eax에 5640EC83
Lea eax, dword ptr ss:[esp+8] :eax에 0x13FF40
Mov eax, dword ptr ss:[esp+8] : eax에 33
12. 기본적인 명령어
• AND, OR ,XOR
비트연산자
XOR는 동일한 오퍼랜드로 처리가능
Ex : XOR EAX, EAX : EAX = 0
• NOP
아무것도 하지 말라는 명령어
• CMP, JMP
비교해서 점프하라는 명령어
• 그 외의 명령어는 구글링
14. 지역 변수 사용
Push ebp
Mov ebp, esp
Sub esp, 50h
• Ebp 레지스터를 스택에 넣는다.
• 그리고 현재 esp의 값을 ebp에 넣는
다.
• Ebp와 esp가 같아지면서 이제 이 함
수에서 지역변수는 ebp에서부터 얼
마든지 계산할 수 있다.
• Ebp를 기준으로 오프셋을 더하고 빼
는 작업으로 스택을 처리할 수 있게
된다.
• Sub esp, 50h LIFO특성으로 인해
특정 값만큼 뺀다는 것은 그만큼 스
택을 사용하겠다는 것이고, 즉 50h
만큼 지역변수를 사용하는 것이다.
15. 함수의 호출
DWORD HelloFunction(DWORD
dwParam1, DWORD dwParam2,
DWORD dwParam3)
HelloFunctioni 호출
Main(){
DWORD dwRet =
HelloFunction(0x37,0x38,0x39);
If(dwRet)
//….
}
Push 39h
Push38h
Push 37h
Call 401300h
• 스택에 값을 LIFO 순으로 넣기 떄문에
실제 소스코드에서 호출한 것과는 반
대로 들어간다.
16. 리턴 주소
• DWORD HelloFunction(DWORD
dwParam1, DWORD dwParam2,
DWORD dwParam3){
• DWROD dwRetAddr = 0;
• __asm
• {
push eax
mov eax,[ebp+4]
mov dwRetAddr, eax
pop eax
}
Printf(“dwRetAddr: %08xn”,
dwRetAddr);
}
• 결과를 보면 HelloFunction()을 호출
한 뒤 호출한 쪽의 다음 번지가 바로 리
턴 주소다.