문제 파일을 다운로드받고 압축을 풀어준다
1. x64bug 해석
본 함수의 코드들인데 여기에서 주목해야 할 점은 correct와 wrong을 출력해주는 부분이다
이 이전에 있는 함수에서 해당 문자열을 고를 반환값을 줬을 가능성이 높기 때문이다
call challo.7FF614ED1000
따라서 위의 코드 속 함수 주소를 더블 클릭 해주면 우리가 해석해야하는 함수의 코드들이 나오게 된다
이 함수에서 쓰이는 어셈블리어 함수 종류
mov | 두 번째에서 첫 번째로 데이터 이동 | jmp | 무조건 분기 |
movzx | 길이가 일치하지 않아도 이동(빈 공간 0) | jae | 결과가 크거나 같으면 분기(부호화 안 된 수) |
movsxd | 길이가 일치하지 않아도 이동(빈 공간 1) | je | 결과 값 0이면 분기(이동) |
sub | 캐리 포함하지 않은 뺄셈 | lea | 오프셋(데이터 영역) 값을 레지스터로 로드 |
add | 캐리 포함하지 않은 덧셈 | xor | 배타논리합(값이 달라야 1) |
inc | 내용 1 증가 | ret | 스택에 push된 주소로 복귀(리턴) |
cmp | 두 인자 내용 비교(같으면 0) | imul | 부호화된 곱셈 연산, 인자가 3개면 |
and | 논리연산 (둘 다 1이어야 1) | 뒤에 있는 인자 두 개 곱한 값 첫 번째 인자에 |
mov: 이전에 사용했던 rcx 속에 있는 수를 rsp+8에 저장해두고
sub: rsp에 18을 빼 메모리를 확장해준다
(= 이 함수 내에서 사용할 스택을 다른 위치로 지정해주는 코드)
rsp, jmp: 반복 횟수를 0으로 초기화해주고 movsxd 명령어가 있는 위치로 무조건 분기한다
movsxd: 반복 횟수를 rax에 넣은 후
cmd, jae: 저장된 반복 횟수가 누적 15면 jae는 포인터를 함수가 끝나는 곳으로 이동시킨다
movsxd, mov: 반복 횟수를 rax에 넣고, 입력값을 rcx에 넣는다
movzx: rcx+rax 즉, 입력값의 반복횟수 번째의 문자를 eax에 넣는다
imul, and: eax에 있는 입력값 문자를 FB와 곱해 저장하고, 이를 또 FF와 and 연산을 수행한다
(imul은 부호화된 곱셈을 다루는 명령어로, FB는 음수를 의미한다)
movsxd, lea: 반복횟수를 rcx에 넣고, 해당 주소에 있는 문자열(정답 문자열)을 rdx에 넣는다
movzx, cmp: 정답 문자열의 반복 횟수 번째 문자를 ecx에 넣고 전 사진에서 얻은 eax와 비교한다
je: 비교한 값이 같으면 함수의 초반으로 다시 돌아가는 jmp chall......1012 명령어로 이동한다
xor, add, ret: 같지 않으면 같은 수를 xor 해 반환 값을 0으로 만들고, 스택을 함수에 들어오기 이전으로 돌린 뒤 함수에서 빠져나오게 된다.
2. Ida 해석
ida는 익숙한 C언어 형태로 디컴파일해줘서 x64dbg보다 훨씬 쉽게 해석할 수 있다
위의 코드를 봐도 correct를 프린트해주는 곳의 if문만 잘 보면 해결할 수 있을 것 같다는 생각이 든다
함수의 디컴파일 버전을 보니까 x64dbg보다 훨씬 이해하기 쉬운 형태를 보여주고 있다
byte_140003000에 있는 정답 문자열이 입력값과
연산 결과값과 같아야 correct를 프린트한다는 걸 알 수 있다
정답 문자열 = -5 * 입력값
정답 문자열이 있는 주소를 더블 클릭하면
Hex View-1창에 해당 위치에 있는 문자열들이 나열돼 있다
우리가 유추한 식을 이용해 c언어를 코딩해 정답을 알아보자
#include <stdio.h>
int main() {
unsigned char chars[] = { 0xAC, 0xF3, 0x0C, 0x25, 0xA3, 0x10, 0xB7, 0x25, 0x16, 0xC6, 0xB7, 0xBC, 0x07, 0x25, 0x02, 0xD5, 0xC6, 0x11, 0x07, 0xC5, 0x00 };
for (int k = 0; k < 21; k++) {
for (int i = 0; i < 256; i++) {
if (((i * 0xFB) & 0xFF) == chars[k]) {
printf("%c", i);
}
}
}
return 0;
}
-5를 곱하고 ff를 and 연산 했을 때 정답 문자열이 나와야 하는 것을 찾아야 하기 때문에
brute force 방식 (전부 대입해보고 찾는 것)으로 코드를 짜본다
마지막에 FF를 and 연산해야 되기 때문에 8비트 단위 내에서만 반복 대입을 실시한다 (i가 256회 반복되는 이유)
무작위 대입을 해 결과값이 정답 문자열과 같은 i를 찾으면 출력하는 형태이다
정답: DH{Did_y0u_brute_force?}
'dreaMhack > Reverse Engineering' 카테고리의 다른 글
[드림핵] rev_basic_9 풀이/어셈블리어 해석 (0) | 2022.04.06 |
---|---|
[드림핵] rev_basic_2 풀이/어셈블리어 해석 (0) | 2022.03.26 |
[드림핵] rev_basic_7 풀이/어셈블리어 해석 (0) | 2022.03.24 |
[드림핵] rev_basic_6 풀이/어셈블리어 해석 (0) | 2022.03.24 |
[드림핵] rev_basic_5 풀이/어셈블리어 해석 (0) | 2022.03.24 |