KGW2027 2023. 4. 16. 00:22
728x90
반응형

x32dbg를 이용한 32-bit 예제 프로그램에 대한 디버깅 및 C코드 추론 작업에 대해 학습함.

1. 어셈블리에 포함된 security_cookie는 Array/Struct가 Buffer-Overflow 되었을 때, 그걸 감지하기 위해 있다.
2. 함수에 파라미터를 입력할 때 or 값을 저장할 때, endian에 의해 값이 거꾸로 저장된다.

참조(주소) 형식
 - 'size' ptr 'ss/ds':['addr']
  : size는 데이터의 크기를 의미하는 것으로, byte(1-byte), dword(2-byte), qword(4-byte)가 있다.
  : ss는 Stack Segment로 지역변수와 같은 스택/힙 영역, ds는 Data Segment로 전역변수와 같은 데이터 영역에 저장한다.
  : addr는 해당 size,ss로 가리키는 곳이 어디인지에 대한 것으로, 메모리 주소에 대해 하드코딩 될수도 있고, ebp 와 같은 레지스터를 이용해 상대주소로 사용될 수도 있다.

 

레지스터의 종류

레지스터 이름 영어명 역할
ebp Base Pointer 현재 함수의 스택 시작 위치를 가리킨다.
esp Stack Pointer 현재 함수의 스택 최상단(다음 Push 위치)를 가리킨다.
eax Accmulator Register 산술연산을 수행하거나, 함수의 반환값이 저장된다.
ecx Counter Register 카운터 레지스터
eip Instruction Pointer 다음에 실행될 명령어가 저장된다.
ST(i), xmm   부동 소수점 연산에 사용되는 레지스터다.

 

어셈블리 명령어

명령어 설명
mov 'addr', 'value' 어떤 주소에 값을 입력한다. 보통 상수 변수 선언 등에 자주 사용된다.
mov 'reg', 'value' 어떤 레지스터에 값을 입력한다. 보통 Mem2Mem 전송이나, 함수 호출(스택 push)등을 위해 중간에 거쳐가는 용도로 자주 사용된다.
lea 'reg', 'ptr' 레지스터에 포인터 값을 입력한다. 예를 들어, 정수형 a가 있을 때, int* b = &a는
lea eax, 'a의 주소'
mov 'b의 주소', eax
같은 식으로 사용된다.
xor eax, eax 자기 자신에 xor하면 0이 나온다는 것을 이용한 최적화 기법이다.
보통 return 0에서 자주 보인다.
cmp r1, r2 r1과 r2가 같은지 subtract를 이용해 확인한다. 이 때 r1, r2의 값에는 변경이 일어나지 않는다.
test eax, eax 자기 자신에 and를 걸어 0인지 아닌지를 확인한다. 보통 if + jmp 용도로 많이 쓰인다고 한다.
push ebp, pop ebp push를 통해 스택에 ebp값을 넣고, pop을 통해 스택의 값을 ebp에 넣는다.

 

main asm 예시

# 함수 시작
push ebp // 이전 함수의 ebp 스택에 저장
mov ebp, esp // 현재 스택 위치를 ebp에 저장. (현재 함수의 시작 위치)

# 지역 변수 할당
sub esp, N // N-byte의 공간을 미리 확보, 매 변수를 push로 할 수 있으나, 최적화 기법임
mov dword ptr ss:[ebp-a], val // ebp에서 a-byte 내려온 위치에 val 입력. (변수 x)
lea eax, dword ptr ss:[ebp-a] // eax에 주소값 저장
mov dword ptr ss:[ebp-b], eax // 변수 y에 x의 주소값 저장

# 함수 호출
call <program._func> // func 함수를 호출한다.

# 함수 종료
xor eax, eax // return 0을 위해 eax를 0으로 세팅한다.
mov esp, ebp // 스택 위치를 초기 위치로 돌려보낸다.
pop ebp // ebp에 이전 함수의 ebp를 입력한다.
ret // ebp와 eip를 이용해 이전 함수로 돌아간다.

 

728x90
반응형