1. Home
  2. 보안 강좌/CodeEngn
  3. [CodeEngn] Basic RCE L03 풀이

[CodeEngn] Basic RCE L03 풀이

문제

비주얼베이직에서 스트링 비교함수 이름은?

 

다운로드

03.exe
0.01MB

 

풀이

문제 자체에서 질문하는건 비주얼 베이직 스트링 비교함수 이름입니다. 그래서 사실 비주얼 베이직으로 만들어진 프로그램들 뜯어서 리버싱을 많이 해봤으면 저 프로그램을 분석 안해도 답을 알 수 있긴합니다.

 

그래도 일단은 03.exe 자체가 비주얼 베이직으로 만들어진 프로그램이기도 하고, 03.exe 안에서 사용된 스트링 비교 함수 이름을 답으로 입력해야 정답으로 인정될 듯 합니다. (비주얼 베이직에서 문자열 다루는 함수가 딱 1개만 있는건 아닙니다.)

 

일단은 03.exe가 무슨 프로그램인지 확인해보기 위해 실행해보겠습니다.

 

어.. 음.. 영어가 아니네요 러시아어 인가..?

 

키니깐 RegCode에 맞는 키를 입력하고 Regist... 버튼을 눌러야 인증이 됩니다.

Reg라는거 보니 가입 코드(Register Code) 를 얘기하는 거 같네요.

어쨌던 항상 하던대로 맞는 시리얼 키(제품 키) 찾는 문제입니다~

 

오늘은 IDA로 분석을 진행해보겠습니다. 제가 이전에 IDA로 비주얼 베이직으로 만들어진 프로그램을 분석하는 것에 대해 자세히 설명을 드렸었는데요 [Abex CrackMe #2] <-- 이 글에서 IDA 사용법이나 구조에 대해 설명을 드렸기에 한번 더 설명을 드리진 않겠습니다. 궁금 하신 분들은 제 Abex CrackMe 풀이 글을 한번 읽어 보고 오시길 바랍니다.

 

아까 Detect it Easy(die) 를 이용해서 분석해서도 알았지만 IDA로 실행 코드를 확인해보니 역시 함수 리턴시 돌아올 주소를 스택에 PUSH하고, 비주얼 베이직의 메인 엔진인 ThunRTMain을 호출하고 있습니다.

 

쉽게 설명해서 C언어에서 main() 함수가 프로그램 시작점(Entry Point)이 됐듯이 비주얼 베이직에서 main() 함수 역할을 하는게 ThunRTMain() 함수 입니다.

저 함수를 호출하는 순간 VB 메인 엔진이 실행되어 VB 프로그램 창이 열리게 됩니다.

 

우선 저 ThunRTMain() 함수 안으로 따라 들어가서 분석을 할 수도 있긴한데 그럼 너무 오래 걸립니다.

Ctrl + 1 을 눌러서 Quick View를 열고 Strings 탭으로 이동해 이 프로그램에서 사용된 모든 문자열을 조사해봅시다.

 

아까 봤던 오류 메세지가 보이네요. 이게 참조되고 있는 코드 위치로 이동합니다.

 

짜잔. 패스워드를 검사하는 분기문이 존재하는 코드를 찾았습니다.

여기서 눈치밥(?)으로 이제 프로그램에서 요구하는 시리얼 키 값을 찾아봅시다.

 

일단 시작 전에 언어 자체가 영어가 아니라서 성공 메세지가 어디에 있는지 모르겠네요 ㅋㅋㅋ 구글 번역기를 사용해보겠습니다.

 

Danke, das Passwort ist richtig !
감사합니다. 비밀번호가 정확합니다!

Error ! Das Passwort ist falsch !
오류! 비밀번호가 잘못되었습니다!

PASSWORT FALSCH !
잘못된 비밀번호 !

러시아어가 아니라 독일어였네요 ㅋㅋ;;

성공 메세지는 Danke.. 부분이였습니다. 이 부분을 찾아봐야겠네요...

 

위로 코드를 좀 올려서 찾아보니깐 성공으로 분기 하는 부분은 바로 저 부분이네요.

그리고 비교를 수행하는 것으로 보이는 부분은 "vbaStrCmp" 라는 부분입니다. 실제로 비주얼 베이직에서 문자열 비교시 사용하는 함수 이름이 바로 vbaStrCmp 입니다. 일단 문제에서 요구하는 답은 찾았는데요. 일단은 끝까지 해서 비밀번호까지 찾고 끝내겠습니다.

 

이 부분만 좀 분석해볼건데요. 올리디버거로 디버깅을 켜고

저 push dword ptr [ebp-58h] 부분부터 브레이크 포인트를 걸고 분석하면서 보여드리겠습니다.

 

 

일단 저 부분에 BP를 걸고 dd라는 값을 입력합니다.

 

분석해야 할 위치로 왔구요. F8로 한 스텝씩 실행하면서 확인해봅시다~~

 

push    dword ptr [ebp-58h]
push    offset a2g83g35hs2 ; "2G83G35Hs2"
call    __vbaStrCmp     ; Call Procedure

우선 앞쪽에서 "2G83G35Hs2" 라는 수상한 문자열과 메모리 위치 [ebp-58h] 에서의 값을 비교하고 있습니다. 

일단 [ebp-58h]에 저장된 값은 뭘까요..?

이건 디버깅을 하면서 따라가면 알게 되는데요. 실제로 [ebp-58h] 위치에 저장된 값이 바로 저희가 입력한 값입니다. 

"2G83G35Hs2" 는 딱봐도 시리얼 값이겠죠?

 

일단 앞쪽에서 저희 입력값과 "2G83G35Hs2" 를 비교한다는 점에서 이 값이 시리얼 값이라는건 거의 확정이 되었습니다..

vbaStrCmp 함수는 문자열 값 2개를 비교하고, 그 결과값을 반환합니다. 

 

반환값을 확인해본 결과, 두 문자열이 같으면 0을 반환하고, 같지 않으면 0이 아닌값을 반환합니다.

 

조금더 저 함수에 대해 자세히 설명드리자면, vbastrcmp 에 대응되는 함수는 마이크로소프트 공식 사이트에서 제공하는 비주얼 베이직 함수 문서 중 StrComp 에 대응되는 것으로 이해할 수 있습니다.

* 물론 정확히는 vbaStrcmp 의 어셈블리 코드 동작을 하나하나 분석해봐야 합니다.

 

기본적으로 vbaStrcmp는 string1, string2 를 비교하게 되는데 string1 이 string2에 앞에 정렬되는 경우 -1, string1과 string2가 같으면 0, string1가 string2 뒤에 정렬되는 경우 1입니다.

 

즉 string1이 string2 앞에 정렬된다는 것은, string1의 string2의 ascii 코드를 하나하나 비교했을 때 string2가 string1보다 ascii 코드 값이 하나라도 커서 string1이 string2보다 앞에서 정렬될 수 있다는 뜻입니다.

부등호로 표기한다면 string1 < string2 일 경우 -1, string1 == string2 일 경우 0, string1 > string2 일 경우 1을 반환한다는 것이죠. 이 설명이 잘 이해안가신다면 C언어 strcmp 함수 설명을 잘 읽어보세요. 실제로 동작은 거의 똑같고 반환값만 양수, 음수가 아니라 1, -1 이라는 것만 다릅니다.

 

어쨌던 간에 vbastrcmp 까지 실행이 끝나면 문자열 비교 결과가 EAX 레지스터에 저장되게 됩니다.

아까전의 함수 호출은 vbaStrcmp("dd", "2G83G35Hs2") 와 같은 형태였으므로, dd가 2G83... 두 문자열을 비교했을 때 d 가 숫자 2보다 ASCII 코드 상으로 나중에 정렬되어야 합니다. 즉 dd > "2G83G35Hs2" 이므로 반환값은 1이겠네요.

EAX값은 1로 반환된다고 생각해볼 수 있습니다.

 

예측대로 EAX 레지스터 값이 1로 설정된 것을 확인해볼 수 있습니다.

그리고 부수적으로 ECX 레지스터도 1로 설정해주네요. 

ECX 레지스터를 1로 세팅해주는 의미는 잘 모르겠습니다 -.-

 

mov     edi, eax
lea     ecx, [ebp-58h]  ; Load Effective Address
neg     edi             ; Two's Complement Negation
sbb     edi, edi        ; Integer Subtraction with Borrow
inc     edi             ; Increment by 1
neg     edi             ; Two's Complement Negation

이후 eax 리턴 값을 edi 레지스터에 이동(복사)합니다. 보아하니 eax 레지스터 값을 변형해서 비교에 사용할 것인데 eax는 함수 리턴값이 계속 들어오는 레지스터라 값이 계속 변화될 가능성이 있으므로 edi 레지스터에 eax를 복사해둔 후 edi에서 처리를 하는듯 싶습니다.

 

이후 lea 명령어를 통해서 우리가 입력한 값의 주소를 ecx로 저장합니다.

 

그리고 edi 레지스터 값을 neg로 부호 반전합니다. 정확히 neg가 어떤식으로 돌아가는 명령어인지는 모르겠는데 IDA가 자동 주석(autocomment) 달아준걸 보니깐 2의 보수라고 하는거보니 그냥 부호를 돌리는 명령어 인거 같습니다.

 

또 sbb, inc, neg 를 통해 다시 edi에 연산을 가해서 값 변형을 가합니다.

 

call    __vbaFreeStr
lea     ecx, [ebp-5Ch]
call    __vbaFreeObj
cmp     di, si
jz      loc_4029DC

최종적으로 vbaFreeStr() 과 vbaFreeObj() 를 우선 호출합니다. 아마 문자열에 할당된 공간과 객체를 할당한 공간을 청소해주는 함수로 보입니다. 힙 공간 Free에 관한 함수가 아닌가 싶네요.

 

최종적으로 cmp di, si를 통해서 EDI 레지스터의 2바이트 부분(di) 과, ESI 레지스터의 2바이트 부분(si) 을 비교해서 같다면 점프를 뛰고, 아니면 실패 구문으로 이동합니다. 아까도 보셨듯이 EDI 값은 문자열 비교 EAX 레지스터에서 리턴된 값에 연산을 가해 변형하여 저장해둔 값입니다.

 

갑자기 ESI 값이 어디서 튀어나왔나 당황할 수 있는데 디버깅을 진행해보면 알겠지만 처음에 시리얼 키를 검사하는 코드가 시작할 때부터 ESI 값은 0으로 세팅되어 있습니다. 그러면 cmp di, si 는 결국 di가 0값인지 체크하는 구문이겠네요.

 

사실 중간에 edi 값에 여러 변형이 이루어져서 vbaStrCmp 에 의해 eax 레지스터로 리턴된 값이 어떻게 바뀌었는진 잘 모르겠습니다만, 일단은 애초에 저희가 입력한 값 "dd" 문자열과 "2G83G35Hs2" 를 비교한다는 점에서 그냥 시리얼키가 거의 빼박이란걸 알 수 있습니다.

 

결론 : 비주얼베이직에서 스트링 비교함수 이름은? => vbaStrCmp

프로그램의 시리얼 키는 ? => 2G83G35Hs2

 

예.. 역시 맞네요! 

 

Danke, das Passwort ist richtig !
감사합니다. 비밀번호가 정확합니다!

근데 성공 창을 왜 경고 아이콘으로 해둔거지?

'보안 강좌 > CodeEngn' 카테고리의 다른 글

[CodeEngn] Basic RCE L06 풀이  (0) 2023.01.12
[CodeEngn] Basic RCE L05 풀이  (0) 2023.01.11
[CodeEngn] Basic RCE L04 풀이  (0) 2023.01.09
[CodeEngn] Basic RCE L02 풀이  (0) 2023.01.05
[CodeEngn] Basic RCE L01 풀이  (0) 2023.01.05
SNS 공유하기
네이버밴드
카카오톡
페이스북
X(트위터)

최근 글 파일의 IT 블로그
추천하는 글 파일의 IT 블로그
최근글
인기글
이모티콘창 닫기
울음
안녕
감사
당황
피폐