문제 파일을 다운로드받고 압축을 풀어준다
1. x64bug 해석
본 함수의 코드들인데 여기에서 주목해야 할 점은 correct와 wrong을 출력해주는 부분이다
이 이전에 있는 함수에서 해당 문자열을 고를 반환값을 줬을 가능성이 높기 때문이다
call challo.7FF675BB1000
따라서 위의 코드 속 함수 주소를 더블 클릭 해주면 우리가 해석해야하는 함수의 코드들이 나오게 된다
이 함수에서 쓰이는 어셈블리어 함수 종류
mov | 두 번째에서 첫 번째로 데이터 이동 | jmp | 무조건 분기 |
movzx | 길이가 일치하지 않아도 이동(빈 공간 0) | jae | 결과가 크거나 같으면 분기(부호화 안 된 수) |
movsxd | 길이가 일치하지 않아도 이동(빈 공간 1) | je | 결과 값 0이면 분기(이동) |
sub | 캐리 포함하지 않은 뺄셈 | lea | 오프셋(데이터 영역) 값을 레지스터로 로드 |
add | 캐리 포함하지 않은 덧셈 | xor | 배타논리합(값이 달라야 1) |
inc | 내용 1 증가 | ret | 스택에 push된 주소로 복귀(리턴) |
cmp | 두 인자 내용 비교(같으면 0) | rol | 왼쪽으로 회전 이동 |
and | 논리연산 (둘 다 1이어야 1) |
mov: 이전에 사용했던 rcx 속에 있는 수를 rsp+8에 저장해두고
sub: rsp에 18을 빼 메모리를 확장해준다
(= 이 함수 내에서 사용할 스택을 다른 위치로 지정해주는 코드)
rsp, jmp: 반복 횟수를 0으로 초기화해주고 movsxd 명령어가 있는 위치로 무조건 분기한다
movsxd: 반복 횟수를 rax에 넣은 후
cmd, jae: 저장된 반복 횟수가 누적 1F를 넘기거나 같아지기 전까지는 jae 명령어를 무시한다
만일 수가 같아지면(for 문이 끝나면) jae는 포인터를 함수가 끝나는 곳으로 이동시킨다
mov, and: eax에 반복 횟수를 저장한 후, 7과 and 연산을 수행한다
movsxd: 반복횟수를 다시 rcx에 넣어 준 후
mov: 그 반복 횟수를 rsp+8에 넣어둔다
mov, movzx: 입력값을 rdx에 넣고, al에 있는 and 연산 값을 ecx에 넣는다
mov, movzx: rsp+8에 넣어 뒀던 반복 횟수를 rax에 넣고, 입력값의 반복 횟수 번째 문자를 eax에 넣는다
rol: 위의 두 값을 rol 연산 해준다
movzx, xor: rol 연산 결과 값을 eax에 넣고, 이를 다시 반복 횟수와 xor 연산을 해준다
movsxd, lea: 반복횟수를 rcx에 넣고, 해당 주소에 있는 문자열(정답 문자열)을 rdx에 넣는다
movzx, cmp: 정답 문자열의 rcx(반복 횟수) 번째 문자를 ecx에 넣고 전 사진에서 얻은 eax와 비교한다
je: 비교한 값이 같으면 함수의 초반으로 다시 돌아가는 jmp chall......1012 명령어로 이동한다
xor, add, ret: 같지 않으면 같은 수를 xor 해 반환 값을 0으로 만들고, 스택을 함수에 들어오기 이전으로 돌린 뒤 함수에서 빠져나오게 된다.
2. Ida 해석
ida는 익숙한 C언어 형태로 디컴파일해줘서 x64dbg보다 훨씬 쉽게 해석할 수 있다
위의 코드를 봐도 correct를 프린트해주는 곳의 if문만 잘 보면 해결할 수 있을 것 같다는 생각이 든다
함수의 디컴파일 버전을 보니까 x64dbg보다 훨씬 이해하기 쉬운 형태를 보여주고 있다
byte_140003000에 있는 정답 문자열이 입력값과
연산 결과값과 같아야 correct를 프린트한다는 걸 알 수 있다
정답 문자열 = 반복 횟수 xor ( rol(입력값, 반복횟수&7) )
입력값 = ror ( (정답 문자열 xor 반복 횟수), (반복 횟수 and(&) 7) )
(rol은 왼쪽으로 회전 이동이라 상쇄시키기 위해서는 ror이라는 오른쪽으로 회전 이동 연산을 사용)
정답 문자열이 있는 주소를 더블 클릭하면
Hex View-1창에 해당 위치에 있는 문자열들이 나열돼 있다
우리가 유추한 식을 이용해 c언어를 코딩해 정답을 알아보자
#include <stdio.h>
int main() {
unsigned char chars[] = { 0x52, 0xDF, 0xB3, 0x60, 0xF1, 0x8B, 0x1C, 0xB5, 0x57, 0xD1, 0x9F, 0x38, 0x4B, 0x29, 0xD9, 0x26, 0x7F, 0xC9, 0xA3, 0xE9, 0x53, 0x18,
0x4F, 0xB8, 0x6A, 0xCB, 0x87, 0x58, 0x5B, 0x39, 0x1E };
unsigned char res = "0";
unsigned char db = "0";
for (int i = 0; i < 31; i++) {
res = i ^ chars[i];
db = i & 7;
char shiftBit = res >> db; //여기에서부터 ror 구현
char carryBit = res << (8 - db);
carryBit &= 255;
printf("%c", shiftBit | carryBit);
}
return 0;
}
정답: DH{Roll_the_left!_Roll_the_right!}
'dreaMhack > Reverse Engineering' 카테고리의 다른 글
[드림핵] rev_basic_2 풀이/어셈블리어 해석 (0) | 2022.03.26 |
---|---|
[드림핵] rev_basic_8 풀이/어셈블리어 해석 (0) | 2022.03.24 |
[드림핵] rev_basic_6 풀이/어셈블리어 해석 (0) | 2022.03.24 |
[드림핵] rev_basic_5 풀이/어셈블리어 해석 (0) | 2022.03.24 |
[드림핵] rev_basic_4 풀이/어셈블리어 해석 (0) | 2022.03.23 |