문제 파일을 다운로드받고 압축을 풀어준다
1. x64bug 해석
본 함수의 코드들인데 여기에서 주목해야 할 점은 correct와 wrong을 출력해주는 부분이다
이 이전에 있는 함수에서 해당 문자열을 고를 반환값을 줬을 가능성이 높기 때문이다
call challo.7FF63A091000
따라서 위의 코드 속 함수 주소를 더블 클릭 해주면 우리가 해석해야하는 함수의 코드들이 나오게 된다
이 함수에서 쓰이는 어셈블리어 함수 종류
mov | 두 번째에서 첫 번째로 데이터 이동 | jmp | 무조건 분기 |
movzx | 길이가 일치하지 않아도 이동(빈 공간 0) | jae | 결과가 크거나 같으면 분기(부호화 안 된 수) |
movsxd | 길이가 일치하지 않아도 이동(빈 공간 1) | je | 결과 값 0이면 분기(이동) |
sub | 캐리 포함하지 않은 뺄셈 | lea | 오프셋(데이터 영역) 값을 레지스터로 로드 |
add | 캐리 포함하지 않은 덧셈 | xor | 배타논리합(값이 달라야 1) |
inc | 내용 1 증가 | or | 논리연산 (둘 중 하나만 1이어도 1) |
shl | 왼쪽으로 shift 연산 (최하위 비트 0) | and | 논리연산 (둘 다 1이어야 1) |
sar | 오른쪽으로 shift 연산 (최상위 유지) | ret | 스택에 push된 주소로 복귀(리턴) |
cmp | 두 인자 내용 비교(같으면 0) |
mov: 이전에 사용했던 rcx 속에 있는 수를 rsp+8에 저장해두고
sub: rsp에 18을 빼 메모리를 확장해준다
mov, jmp: 반복 횟수 저장하는 rsp에 0을 넣어주고 7FF63A09101A로 분기한다
movsxd, cmp: 반복 횟수를 rax에 넣고 1C와 비교한다
jae: for문이 작동되는 구간으로, 반복 횟수가 1C보다 크거나 같은 경우 함수의 마지막 부분으로 분기한다
movsxd: rsp에 있는 반복 변수를 rax에 넣고
mov: rsp+20에 있는 입력받은 문자열 위치를 rcx에 넣고
movzx: 입력받은 문자열의 n번째 문자를 ecx에 넣는다
sar: 해당 문자열에다가 오른쪽 shift 연산을 수행한다
movsxd: rsp에 있는 반복 변수를 rcx에 넣고
mov: rsp+20에 있는 입력받은 문자열 위치를 rdx에 넣고
movzx: 입력받은 문자열의 n번째 문자를 ecx에 넣는다
shl: 해당 문자열에다가 왼쪽 shift 연산을 수행한다
and: 위의 연산을 한 값을 F0과 and 연산해 주고
or: and 연산 결과값과 오른쪽 shift 연산을 했던 값을 or 연산해준다
movsxd, lea: rsp 반복 횟수 값을 rcx에 넣고, 정답 문자열을 rdx에 넣어준다
movzx: 반복 횟수 값과 정답 문자열을 더해(=n번째) 문자를 ecx에 넣는다
cmp, je: 정답 문자열과 연산한 값을 비교해 같은 경우 7FF63A091063로 분기한다
jmp: 분기했을 경우 함수의 초반으로 돌아가 for 문을 돌고, 분기에 실패했을 경우
xor: 두 값이 달라야 1을 돌려주는 논리연산을 같은 값끼리 해 함수의 반환 값을 0으로 설정해준다
add: rsp에 18을 더해 이 함수에서 사용하던 스택을 빠져나오고
ret: 리턴해준다
2. Ida 해석
ida는 익숙한 C언어 형태로 디컴파일해줘서 x64dbg보다 훨씬 쉽게 해석할 수 있다
위의 코드를 봐도 correct를 프린트해주는 곳의 if문만 잘 보면 해결할 수 있을 것 같다는 생각이 든다
함수의 디컴파일 버전을 보니까 x64dbg보다 훨씬 이해하기 쉬운 형태를 보여주고 있다
byte_140003000에 있는 정답 문자열이 입력값과
연산 결과값과 같아야 correct를 프린트한다는 걸 알 수 있다
정답 문자열 = (16 * 입력값) or (입력값 오른쪽으로 4번 shift 연산)
( |: or 연산자 )
비트 곱셈은 입력값 * 2 ^ 4 (2의 4승)으로 나타낼 수 있고, 이는 왼쪽으로 shift연산 4회를 의미하기도 한다
= (입력값 왼쪽으로 4번 shift 연산) or (입력값 오른쪽으로 4번 shift 연산)
입력값 = (정답 문자 왼쪽으로 4번 shift 연산) or (정답 문자 오른쪽으로 4번 shift 연산)
위의 계산은 상위 4비트와 하위 4비트 위치 변경과 같은 연산이라 입력값 구할 때도 같은 연산 사용
정답 문자열이 있는 주소를 더블 클릭하면
Hex View-1창에 해당 위치에 있는 문자열들이 나열돼 있다
우리가 유추한 식을 이용해 c언어를 코딩해 정답을 알아보자
#include <stdio.h>
int main() {
unsigned char chars[] = { 0x24, 0x27, 0x13, 0xC6, 0xC6, 0x13, 0x16, 0xE6, 0x47, 0xF5, 0x26, 0x96, 0x47,
0xF5, 0x46, 0x27, 0x13, 0x26, 0x26, 0xC6, 0x56, 0xF5, 0xC3, 0xC3, 0xF5, 0xE3, 0xE3 };
for (int k = 0; k < 28; k++) {
printf("%c", (chars[k] >> 4) | (chars[k] << 4));
}
return 0;
}
정답: DH{Br1ll1ant_bit_dr1bble_<<_>>?}
'dreaMhack > Reverse Engineering' 카테고리의 다른 글
[드림핵] rev_basic_6 풀이/어셈블리어 해석 (0) | 2022.03.24 |
---|---|
[드림핵] rev_basic_5 풀이/어셈블리어 해석 (0) | 2022.03.24 |
[드림핵] rev_basic_3 풀이/어셈블리어 해석 (0) | 2022.03.23 |
[드림핵] rev_basic_1 풀이/어셈블리어 해석 (0) | 2022.03.23 |
[드림핵] rev_basic_0 풀이/어셈블리어 해석 (0) | 2022.03.23 |