security/리버싱 - CodeEngn.com

BASIC RCE L01~L05

민사민서 2023. 4. 9. 17:20

L01. HDD to CD ROM

실행시켜보니 "Make me think your HD is a CD-Rom" 문자열 가진 MessageBox 등장
확인 누르니 "Nah... This is not a CD-ROM Drive!" 문자열 가진 MessageBox 등장

코드 분석해보니 kernel32!GetDriveTypeA("c:\") 호출 후 리턴값을 받아서
EAX는 2 감소시키고 (API 호출 후 리턴값: 일반 실행 시 3)
ESI는 3 증가시킨 후 (API 호출 직후 64bit Win10 PC에선 401000[Entry Point]로 세팅. 32bit Win7 PC에선 0)

CMP EAX, ESI 해서 같으면 성공, 다르면 실패
- CMP 시 ESI = 0x3이다, EAX=0x1이다
=> 성공 MessageBox 출력되려면 EAX = 0x5여야 함?

L02. 손상된 파일의 PW

일반 실행 / ollydbg로 open => 둘 다 실행 실패
HXD로 열어보니
- IMAGE_DOS_HEADER 존재, NT Header offset 0x1000 ?? (근데 파일크기가 0xD50이다)
- 0x108부터 섹션 헤더 4개 존재 (.text, .rdata, .data, .rsrc)
- 각 섹션의 RAW는 0x400, 0x600, 0x800, 0xA00 임


- .data 섹션 부근 (0x750~0x7A0)에 읽을 수 있는 문자열 존재
ADDialog�ArturDents CrackMe#1��������Nope, try again!�Yeah, you did it!�Crackme #1�JK3FJZh
=> "Yeah, you did it!" 뒤의 문자열 "Crackme #1JK3FJZh" 의심스러움


- .rsrc 섹션 부근 문제 푸는 방식에 대한 힌트 존재함
R�u�l�e�s�:� �J�u�s�t� �f�i�n�d� �t�h�e� �u�n�l�o�c�k� �c�o�d�e�,� 
�n�o� �p�a�t�c�h�i�n�g� �a�l�l�o�w�e�d�.� 
�I�t�'�s� �v�e�r�y� �e�a�s�y�,� �s�o� �d�o�n�'�t� �e�x�s�p�e�c�t� �t�o� �m�u�c�h�

=> UNICODE로 "Rules: Just find the unlock code, no patching allowed. It's very easy, so don't exspect too much"

결국 JK3FJZh 가 답이었음 ㅋㅋ

 

cf) 이걸 진짜 복호화한 사람이 있네

https://github.com/codeengn/codeengn-challenges-writeups/blob/master/RCE_Basic/L02/RCE%20Basic%20L02%20Report%20%5BL3m0nTr33%5D.pdf

 

GitHub - codeengn/codeengn-challenges-writeups: CodeEngn Challenges Best Writeups

CodeEngn Challenges Best Writeups. Contribute to codeengn/codeengn-challenges-writeups development by creating an account on GitHub.

github.com

L03. 올바른 PW를 구하고, NAG를 제거하기

실행하면 "entferne diesen Nag, oder bekomme das richtige passwort heraus!" 이런 Nag 뜬다
파파고의 도움을 받아 독일어를 해석하면 "remove this nag, or get the right password!"

확인 버튼 누르면 등록 창이 뜬다, Regcode 입력 가능하고 Register / Exit 버튼 존재
Register 버튼 누르면 "Error ! Das Passwort ist falsch !" 이런 메시지박스 뜬다

1) 일단 문제에서 요하는 Visual Basic의 문자열 비교함수 이름을 구해보자
module 03에서 Search for all referenced strings에서 저 실패 문자열을 참조하는 주소로 가면
password 대조하는 루틴 근처로 jump 한다

좀만 위로 올라가보면 MSVBVM50.__vbaStrCmp 결과 (EAX)에 따라 분기 나뉜다
=> __vbaStrCmp

2) password를 구해보자
__vbaStrCmp의 첫번째 인자가 UNICODE "2G83G35Hs2" 였다

3) 실행 초기에 뜨는 Nag를 없애보자
module 03에서 Search for -> All Intermodular calls에서 MSVBVM50!rtcMsgBox() 호출하는 부분에 모두 bp (4개의 호출)
- 실행 초기에 뜨는 Nag는 00402CFE에서 bp

- 메인 창 상단의 옵션(?er) 누르면 00402E4C에서 bp
- Register 버튼 누르면 PW 틀렸을 경우 00402AE8에서 bp, PW 맞췄을 경우 00402977에서 bp
- 메인 창은 rtcMsgBox API랑 관련없음
=> 00402CFE의 호출만 무력화시키면된다
=> CALL 00401120 - JMP DWORD PTR DS:[~] - API 코드 실행
=> 초기 NAG가 떴을 때 확인 누르면 EAX=1, 취소 누르면 EAX=2로 세팅된다
=> 함수 호출부(00402CFE)의 다섯바이트를 MOV EAX,1 로 바꾸면 되겠다

L04. 프로그램의 디버거 탐지 루틴 파악

일반 실행해보니 터미널 뜨고 매 초마다 "정상" 이라는 메시지 뜸
=> 시간 기반 탐지기법..? (No)

EP에 바로 SEH 설치 코드 존재하네

SEH Handler 코드 가봤더니 코드 시작 전에 시그니쳐(Unicode 값) 존재 // VC20XC00

=> 에러 의도적으로 발생시켜서 SEH에서 디버거 탐지하는 식..? (No)

EP에서 쭉 트레이싱하다보니 00408454에서 "CALL 0040100F" 명령어를 step over 하면
프로그램 실행되면서 "디버깅 당함" 문자열 계속 뜬다. 40100F 서브루틴이 디버깅 탐지 루틴임을 알 수 있다
0040100F에서는 바로 00401030로 점프

00401030 함수를 쭉 분석하다보면 반복문 등장한다
REP STOS DWORD PTR ES:[EDI]
// ECX에 저장된 횟수만큼 EDI가 가리키는 곳에 EAX 값을 저장한ㄷ다
// 반복 시마다 ECX 1씩 감소, EDI 1씩 증가

sleep(1000) 후 kernel32!IsDebuggerPresent API 호출해서 => 디버깅 탐지 함수!!
리턴값이 0이 아니면 "디버깅 당함" 출력
리턴값이 0이면 "정상" 출력

cf) IsDebuggerPresent API는 내부적으로 PEB.BeingDebugged 멤버 값을 참조해서 디버깅 중인지 판단한다

L05. 패킹되어있는 프로그램의 등록자명 / 시리얼키 파악

Name/Serial을 입력하고 Register 버튼 눌러서 확인하는 흔한 Crackme..
실패할 경우 "Wrong Serial,try again!" 메시지박스 출력됨

Ollydbg로 열어보니 unpacking 과정을 거치더라
HXD로 열어보니 파일의 섹션이 UPX0, UPX1, .rsrc 존재

- UPX로 패킹되어있음. unpack 해보자
- upx.exe와 동일한 폴더로 05.exe를 복사 후 upx -d 05.exe 하면 된다 (132608에서 315392로 크기 증가)
cf) 꿀팁아닌꿀팁: 파일탐색기 경로 입력 창에 cmd 입력 후 실행하면 해당 디렉터리에서 터미널 실행 가능

 

Search for - All referenced Strings로 실패 문자열을 검색한 결과
success 출력하는 루틴 하나(이름 시리얼 둘 다 맞출 경우), fail 출력하는 루틴 둘 (이름 틀리거나, 시리얼 틀리거나)

 

메인 함수 분석한 결과
- CALL 0043D068 은 입력한 문자열을 메시지박스로 출력하는 루틴
- CALL 00420E20 은 로컬변수(EBP-0x4)에 name 혹은 serial 문자열 주소를 저장하는 루틴
- CALL 00403B2C 은 EAX, EDX에 담긴 문자열 비교하는 루틴

메인 함수의 맨 처음(00440EB0)부터 분석해보면
1) SEH 추가 (0x00440FBA)

2) Local변수(EBP-4)에 name 문자열 주소를 저장 후 NULL(0x0)인지 check
3) Local변수(EBP-4)에 serial 문자열 주소를 저장 후 NULL(0x0)인지 check

4) Local변수(EBP-4)에 name 문자열 주소를 저장 후 "Registered User"와 같은지 비교
5) Local변수(EBP-4)에 serial 문자열 주소를 저장 후 "GFX-754-IER-954"와 같은지 비교=

문자열 비교 루틴을 좀 더 자세히 살펴보자
- Hex Dump로 확인해보니 문자열 시작 주소의 앞 4바이트에는 문자열 길이 들어있음

- ESI에 User input 문자열의 주소를 담고, EDI에 정답 문자열의 주소를 담음

- EAX에는 User input 문자열의 길이를 담고, EDX에는 정답 문자열의 길이를 담음
- 403B49 ~ 403B4F 연산을 통해 EDX에 Min(User input 문자열 길이 , 정답 문자열 길이) 를 담고 // 비교할 길이!!
- 4로 나눠서 4바이트씩 비교 몇 번 해야되는지 파악

- 비교 길이가 4보다 크면 루프 안에서 4바이트씩 반복해서 비교하고

- 루프 밖에서 나머지 바이트 비교 후 결과값 리턴

보니까 Name에는 "Registered User", 시리얼에는 "GFX-754-IER-954" 입력해야 되겠네
IDA로 분석하면 디컴파일 상태에서 할 수 있어 훨 간단하다 (Find Text로 바로 메인함수로 이동 가능)

느낀점: 리버싱 핵심원리는 GOD이다

 

 

 

 

 

'security > 리버싱 - CodeEngn.com' 카테고리의 다른 글

Advance RCE L01 ~ L07  (0) 2023.04.20
Basic RCE L16~L20  (0) 2023.04.16
Basic RCE L11~L15  (0) 2023.04.13
BASIC RCE L06~L10  (0) 2023.04.11