달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

이번 문제는 ELF 파일구조에 대한 문제였다. 


ELF 파일 리버싱은 익숙하지 않기도 하고, 도대체 익숙한건 뭔지- -,  말로만 듣던 난독화 기법 중 가상머신이 적용된 내용이라 사전학습이 좀 필요했다. 개념을 잡기에 괜찮은 사이트를 하나 발견했는데 아래에 주소를 적어놓았으니 관심있는 사람은 한번쯤 읽어볼만 하다. 


간단히 가상머신 기법에 대한 설명을 하자면,

실행 프로그램안에 별도의 OPCODE를 정의하고 해당 OPCODE가 동작할 수 있는 기반을 마련하여 개발자가 정의한 OPCODE로 프로그램을 동작하는 것이다. 그러기 위해선 일단 사용자가 정의한 OPCODE가 동작할 수 있는 메모리(스택, 레지스터 등)가 필요하고 정의한 OPCODE가 어떻게 동작하는 지에 대한 정의는 필수적이다. 



그럼 문제풀이를 시작하도록 하겠다. 


우선 문제를 동작시키면 아래와 같은 형태로 실행된다. 여러 다른 문제들과 같이 프로그램 내에 정의된 값을 맞추는 것이다. 



내부를 보기 위해 디스에셈블러를 이용하여 한번 열어보았다. 그러니 아래처럼 툴이 정상적으로 캐치를 하지 못한다. 





처음부터 호락호락하지 않은 문제구나 싶었다. :( 

왜 그럴까 싶었는데 프로그램의 EP가 프로그램 헤더에서 정의한 영역을 벗어나서 그런거 같았다. 그래서 현재 EP에 있던 명령어를 실행한 뒤 상태로 만들어놓고 EP를 수정한 뒤 다시 로드하니 아래처럼 인식을 하게 되었다. 




근데 저 위에 로직은 문제 해결에 핵심적인 부분은 아니다. 이는 문제를 생성하기 위한 기반을 만드는 로직인 것 같다. 뭐 메모리를 할당하고 해당 메모리에 별도의 실행 로직을 만들고 파기했다가 어쩌구 저쩌구 한다. 이런저런 행위가 지나고 나면 프로세스는 0x8048000-0x804a000 범위로 IP를 옮기게 된다.  


위에서 언급한 메모리를 덤프떠서 디스어셈블러 툴에서 열어보면 흐름을 파악할 수가 있다. 


대충 핵심만 얘기해보자면 프로세스는 자식 프로세스를 생성하고 생성된 자식 프로세스에서 Input: 에 입력된 값과 OPCODE 셋을 부모 프로세스에게 전달해준다. 이를 전달받은 부모 프로세스는 OPCODE 셋에 특정 연산을 한 뒤 저장하고 이를 활용하여 자신만의 OPCODE를 실행하게 된다. 


아래는 OPCODE 셋이 저장되어 있는 메모리다. 아래의 캡쳐를 간단히 설명하자면 빨간색 박스에 위치한 값이 내가 입력한 값이고 노랑색 박스는 내가 입력한 문자와 추가로 연산이 될 값이 저장되는 위치, 초록색 박스는 실행될 OPCODE의 인덱스(EIP와 같이)가 저장되는 위치이다. 
초록색 박스 뒤에는 연산자와 피연산자가 쭈우우욱 이어져있다. 



아래의 캡쳐는 위의 OPCODE 셋에 정의된 명령어를 실행시키는 반복문이다. 




바로 위 두개의 캡쳐가 이번 문제를 풀기 위한 핵심이다. 위 부분을 잘 분석하면 답을 얻을 수 있다. 



짜잔 ~ 


가상머신 난독화 기법에 대한 개념을 잡아보기에 좋은 문제인 것 같다. 좋은 경험이었다 :)



Reference

[1] Reversing Engineering Virtual Machine Protected Binaries, 

    http://resources.infosecinstitute.com/reverse-engineering-virtual-machine-protected-binaries/

:
Posted by einai
2017. 7. 7. 12:47

[문제풀이] reversing.kr - CSHARP Wargames/reversing.kr2017. 7. 7. 12:47

이번 문제는 닷넷 리버싱 관련 문제이다. 이전에도 닷넷 문제가 있었으나 블로깅은 하지 않았다. 


보통 닷넷 문제는 디컴파일러를 이용해서 문제를 해결한다. 이번 문제도 물론 디컴파일러(JetBrains dotPeek)를 이용했다. 하지만 이번 문제는 디컴파일러로만 해결할 순 없었다. 이와 더불어 디어셈블러(ILDasm.exe), 헥스에디터(Hxd)도 활용했다. 


CSHARP은 여러가지 방법으로 접근해서 문제를 해결할 수 있었다. 


우선 문제가 어떤식으로 출제됬는지 확인한 뒤 다시 논하도록 하겠다. 



프로그램을 실행시키면 위와 같은 화면이 뜨고 문자열을 입력한 뒤 Check를 입력할 경우 "Correct!!" 또는 "Wrong" 팝업을 띄운다. 그럼 디컴파일러를 이용하여 로직을 살펴보도록 하자.


우선 생성자 부분을 확인해보도록 하겠다. 



생성자 부분에서는 "MetMett" 함수 바디에서 MSIL 바이트를 배열 단위로 가져온 뒤 byte[] 에 삽입한다. 그 뒤에 반복문과 특정 값 대입을 실행한 뒤 InitializeComponent 함수를 호출한다. 해당 함수는 화면 구성과 이벤트 핸들러 등록 등 그닥 살펴볼 부분이 없기 때문에 넘어가도록 하겠다. 


MetMett 함수의 몸체는 아래와 같이 디컴파일에 실패한다. 



그 뒤 "MetMetMet" 함수가 존재하는데 프로그램에서 "Check" 버튼을 눌렀을 때 발생하는 함수다. 여기서 어셈블리가 동적으로 생성된다. 닷넷 프로그램에서 사용되는 어셈블리라는 개념은 흔히 사용하는 어셈블리 언어와 개념은 다르나 여기서는 크게 유념치 않아도 될 것 같다. 여기서는 단순히 하나의 동적 함수를 생성한다 정도로만 받아드리면 될 듯 하다(정확한 의미는 아님).



바로 위의 캡쳐를 잘보면 Form1 클래스의 생성자에서 생성된 Form1.bb 배열을 이용하여 메소드를 생성한다. 여기까지만 보면 대충 느낌이 오지 않는가 ?! 


위에서 문제를 풀 수 있는 방법에 대해 언급하다만 내용을 다시 얘기해보겠다. 

크게 두가지 방법으로 접근해서 해당 문제를 해결할 수 있겠다. 


첫 번째, MetMett 함수의 hex 값을 가져와서 수동으로 변조한 뒤 바이너리 파일의 hex 값을 덮어쓰는 것 

두 번째, 디버거를 이용하여 동적 어셈블리가 생성되어 호출될 곳에 BP를 걸고 분석하는 것 


각 방법에 대한 자세한 방법은 따로 기재하지 않겠다. 


우선 첫 번째 방법을 이용하여 hex 값을 수정한 뒤 디스어셈블러를 이용해 불러보면 아래와 같이 나타난다. 



그리고 두번째 방법을 이용하여 접근했을 경우는 이렇다. 



문자열 비교 로직은 여지껏 진행해 온 문제들과 다르지 않다. 한가지 정도 다른데 다들 눈치챘을거라 생각하고 ~슥 





빠밤~~ 미션 컴플릿 !!

:
Posted by einai
2017. 7. 7. 12:46

[문제풀이] reversing.kr - Lotto Wargames/reversing.kr2017. 7. 7. 12:46

이번 문제는 64비트에서 실행되는 것 외에는 특별한게 없었던 문제였다. 


문제를 풀기 전에 알아야 할 건 64비트에서는 어떻게 함수에 파라미터를 전달하느냐 정도이다. 64비트 프로그램은 기존 방식과 다르게 총 4개의 레지스터를 사용하여 파라미터를 전달하고 그 이상 파라미터가 존재할 경우 스택을 이용한다. 


사용되는 레지스터 (순차적으로)

 - 정수형 : RCX, RDX, R8, R9 

 - 실수형 : XMM0, XMM1, XMM2, XMM3



그럼 문제풀이를 진행해보도록 하겠다. 


문제는 문제 이름을 보면 알수있듯이 랜덤으로 생성되는 6개의 수를 맞추는 것(또는 우회)이다. 

그럼 퀵하게 한번 보도록 하겠다. 


우선 문제를 시작하면 아래와 같이 동작한다. 여기서 숫자는 내가 임의로 입력한 값이다. 



로직을 살펴보도록 하겠다. 아래 보이는 부분은 wscanf_s 함수를 호출하는 부분이다. 

특별한 건 없고 어디에 내가 입력한 값이 저장되는지 정도만 확인하고 넘어가자.



아래 캡쳐는 6개의 수가 어떻게 생성되는지 나타낸다. rand 함수를 호출하고 곱셈, 쉬프트 연산 등등을 이용해서 값을 생성해낸다. 



아래 부분은 단순히 내가 입력한 값과 바로 위에서 생성된 값을 비교한다. 총 6번 비교를 진행한다. 



머 어찌저찌 위 비교 로직을 통과하게 되면 문제에 대한 해답을 나타내주는 부분이 진행된다. 

여기선 따로 분석을 진행하지 않겠다.



위 부분이 쭉쭉 지나고 나면 답을 출력해준다. 



Clear!

:
Posted by einai

음 이번 문제는 못풀었다고 보는게 맞다. 


문제 초기에 완전 혼자 딴 생각에 빠져서 삽질만 겁나 하다가 지쳐서 검색했다. 

나는 왜 이것을 키젠 문제라고 생각했을까 ? ㅠㅠ


문제에 원본 프로그램과 패킹된 프로그램 두개를 떡하니 넣어놓고 

패커 탐지툴도 탐지했었는데 패스워드 체크란 타이틀만 보고 덥석 패스워드 푸는것만 생각하고

다른 생각을 아예 하지 못했다. 원래 입력된 값을 어떻게 추측할 수 있을까만 내내 고민했다.


좀 더 다양한 측면에서 생각할 수 있도록 하자. !!


고로, 이번 문제는 문제풀이 대신 참고한 사이트를 게시하도록 하겠다. 



thx to http://revers3r.tistory.com/9 

:
Posted by einai

이번 문제는 이전에 푼 AutoHotkey1 문제와 유형이 다른 문제였다. 


인터넷에서 알아보니 오토핫키 프로그램은 컴파일 시 자동으로 UPX 패커를 적용시킨다고 나와있었다. 

근데 내가 테스트해봤을 땐 자동으로 패킹되진 않았다(옵션이 있나,, 아님 수동으로 적용시키는건가,,).  


어째든 이번 문제는 오토핫키 실행파일이 정상적으로 작동되지 않는 걸 동작시키는게 목표다. 우선 문제를 다운받아 압축을 풀어보자. 



이번에도 실행파일과 나를읽어 파일로 구성되어 있다. 

나를 읽어 파일을 읽어보자. 



동작하기 위해선 수정을 해야한단다. 우선 동작시켜보자 !! 



음.. 사실 이 에러는 이전에 AutoHotkey1 문제에서 언패킹을 한 뒤에도 동일하게 나타났던 현상이다. 그땐 문제를 해결하는데 언패킹이 필요가 없는 걸 깨닫고나서 더 이상 알아보지 않았다.  

근데 이번 문제는 그냥 실행하자마자 이 화면이.. 그리고 이것을 해결해야 답을 알수있으니.. 어쩔수 없이 분석을 진행해야했다. 



에러를 발생시키는 곳을 찾아가는 것은 어렵지 않으니 생략하도록 하겠다. 

아래 캡쳐는 문제가 발생되는 곳을 그래프로 표현한 것이다. 



처음엔 그냥 대충대충 분석안하고 플래그 변조나 하면서 지나갔는데 에러가 발생했다. 

역시 제일 빠른 건 차근차근 원인을 분석하는 것이었다. 어차피 결국 분석할테니까... ㅠㅠ 



위 구문을 봐서 알겠지만 함수명이 표현되지 않는다. 

추측인데 특정 함수를 인라이닝해서 컴파일해서 그런 것 같다. 


다행스럽게도 아이다님께선 함수를 알고 계셨다. 


어째든 여기서 사용되는 몇몇 함수는 파일 관련 함수였다. 읽고 위치 변경하고 하는.. 

조금 내려가다보면 프로세스에서 어떤 값을 저장한다. 이것도 역시 나중에 나를 물맥이려고 하는 수작이다. 



0x10 크기만큼 어떤 값을 가져와 어떤 위치에 저장한다. 

그리고 이어서 ~ 



우선 파일의 위치를 변경하고 특정 값을 읽어온다. 위에서 읽어오는 값이 이후에 비교될 값의 대상이 된다. 게다가 읽어온 값이 어떠냐에 따라 프로세스가 뻗어버리던지 돌아가던지 한다. 음음. 



여기서는 파일을 무결성을 검증하기 위한 값을 만든다. 간단하게 말하면 파일의 값을 가져와서 XOR 연산을 한뒤 위에서 읽어온 값 중 하나와 비교한다. 여기는 뭐 그냥 쩜프만 뛰어도 충분하다. 



그 다음에 위에서 0x10 크기만큼 가져온 값과 파일의 내용을 참조해서 비교한다. 

0x10 크기만큼 다 맞으면 통과 !! 위에서 힌트가 있으니 이 값만 맞추면 왠만하면 문제없이 동작할 것이다.


하지만 동작한다고 해서 끝이 아님!!

이번엔 동작한 프로그램에서 문제가 나타난다. 

인터넷 검색하니까 금방 답이 나오긴 했지만 :) 


어째든 동작한 프로그램은 이렇게 생겼다. 



끄으으읏!!


:
Posted by einai

이 문제는 블로그에 안쓸까 했따. 


문제 의도만 알아채면 어렵지 않은 문제라, 

사실 다른 분들이 만들어놓은 디컴파일러 때문에 쉽게 풀렸다고 보는게 맞겠다. 


우선 AutoHotkey 가 무엇인지 알아보자. 


AutoHotkey ?

AutoHotkey는 매크로를 오픈소스 프로그램이다. 이를 이용하면 반복적인 작업을 간결하게 만들 수 있고 각종 단축키를 지정할 수 있다. 이를 스크립트로 이용할수도 있고 컴파일해서 실행파일로 변환하여 사용할 수도 있다. 


간략히 이정도만 알아보고 문제풀이에 들어가겠다. 


일단 문제를 다운받아 압축을 풀면 아래와 같은 구성으로 되어있다. 






나를읽어.txt 파일을 읽어보겠다. 



어떤 해쉬 값의 원래 값을 알아내서 조합하는 게 이 문제의 답이다. 


하지만 어떻게 알아낼까 ?! 원래 해쉬 함수는 함수의 출력 값을 이용해서 입력 값을 알 수 없는 법이다. 하지만 일부 사이트에서 다량의 해쉬 함수의 결과 값과 입력 값을 수집하여 매핑시켜 놓고 검색을 허용해준다. 아마 이 문제도 그걸 노리는 것 같았다. 사실 이 느낌 반과 다른 트릭이 있을 거 같단 느낌 반반이었다.  그래서 약간의 삽질 좀 했쥐..


우선 나도 오토핫키를 처음 봐서 DecryptKey가 뭔지 몰랐다. 또한 Exe's Key 도 무슨뜻인지 단번에 와닿진 않았다. 

어째든 오토핫키에 대해 검색을 하다보니, 오토핫키를 컴파일하는 과정에 패스워드를 입력할 수 있고 이를 이용하여 무분별한 디컴파일을 막는 것 같았다. 하지만 입력한 패스워드가 평문으로 저장되고 찾기가 용이한 듯 보였다(실제 분석하진 않았음). 



주저리 주저리 떠들다 보니 문제 실행 사진을 안올렸군...

문제를 실행했을 때는 아래와 같다. 




What a simple window..


어째든 , 이를 디컴파일할 수 있는 툴이 인터넷에 돌아당기고 쉽게 찾을 수 있땅.

또한 패스워드를 입력하지 않아도 자동으로 패스워드를 검출해주고 디컴파일까지 해주는 프로그램도 존재한다.


어째든 해당 툴을 이용하면 패스워드가 노출되고 이 값이 DecryptKey 가 된다. 

그리고 디컴파일되면 간단한 해쉬값이 나오는데 이 값이 Exe's Key 값이 된다. 


해당 해쉬 값들을 해쉬 함수 검색 사이트에서 검색하면 금방 해쉬 함수의 입력 값을 찾을 수 있다. 

처음에 시도한 해쉬 함수 검색 사이트에서 찾아내질 못해서 괜히 딴생각하고 삽질했었음..ㅠㅠ


이렇게하면 게임 클리어!!

:
Posted by einai

이번 문제는 랜섬웨어를 표방한 게임이었다.


문제의 난이도는 어렵지 않았지만 자칫 잘못된 상상을 하게 되면 헤맬수도 있을거 같다는 생각을 했다. 실제 잘못된 상상을 하고 몇번 실행에 옮겼지만 괜히 스스로가 오바하는 기분이 들어 멈췄다.


사실 이 문제보다 Twist1을 먼저 풀었는데 문제 배점 자체도 더 낮을 뿐더러 푼 사람도 훨씬 많아서 너무 어렵게 생각안해도 되겠지 싶어 잘못된 상상을 고쳐 먹었다.



패킹이 되어 있었는데 언패킹 과정은 어렵지 않으니 생략하고 바로 본론으로 넘어가겠다.

그럼 문제풀이를 시작해보겠다.




문제파일을 다운로드받고 해제했을 때 위와 같이 3개의 파일로 구성되어 있었다. 바로 readme.txt 파일을 확인해보았다. 



파일을 복호화하란 메시지였다. 저 괄호안에 있는게 나름 중요한 힌트였다. file 파일이 복호화가 되면 실행파일로 변환된다. 여기서 힌트를 흘려봤으면 복호화해도 또 엉뚱한 짓을 하느라 시간을 소비했을 수도 있다.  



파일을 실행시켜보았다. 위와 같은 메시지를 내보내고 키 값을 입력 받는다. 다행히 코드 배포자가 굉장히 나쁜사람이지만 약속은 지키는 사람이란다. 단, 여기서도 힌트가 존재하는데 잘못된 키를 넣었을 경우 파일이 더욱 훼손되는 것이다(내부 흐름을 보면 알겠지만 자신이 입력한 값이 무엇인지 순서대로 적어놓기만 하면 복호화하는덴 문제없다).



위에 캡쳐는 단순히 화면에 메시지를 출력하고 키 값을 입력받는데 사용된다. 이하 중요하지 않은 부분은 캡쳐를 포함하는 대신 간단히 말로 설명하겠다. 


이후에 내가 입력한 문자열 길이를 저장하고 파일의 내용을 가져오고 머 이런저런 작업을 한다. 뭐 복호화를 하기 위한 사전 작업이랄까나..



이게 핵심 로직이다. 복잡하지 않고 굉장히 심플하다. XOR 연산을 두번에 걸쳐 진행한다. 

내가 입력한 값과 파일의 값을 문자 단위로 XOR 연산하고, 0xFF로 다시 연산한다. 이게 끝이다. 


사실 처음에 딱 이것만 봤을 때 XOR 연산인데 내가 어떻게 원래 값을 확인할 수 있을까 싶었다. XOR 역연산을 하기 위해선 XOR연산에 사용한 값을 알아야 하기 때문에 ..!!  



파일의 특성(사실 특성이랄것도 없지만)과  XOR 연산의 특성을 인지하고 있다면 위의 캡쳐만 봐도 굉장히 쉽게 풀릴 것이다. 


간략히 해결방법을 나열하자면 이렇다. 

1. 파일은 0x00으로 채워진 공간이 존재한다.

2. XOR 연산은 같은 값으로 두번 연산할 경우 원래의 값으로 돌아간다. 


다들 감이 왔을거라 본다. 



위의 캡쳐는 암호화 된 파일의 최하단 부분이다. 딱 보면 일정한 길이로 반복되는 문자열이 존재한다. 이를 위의 XOR 연산을 대입하여 계산하면 어떤 문자가 나타난다. 

이를 이용하면 복호화가 진행되고 복호화가 진행된 후 파일의 확장자를 exe로 변경하고 실행시키면 해답이 나온다.




빠밤!

:
Posted by einai

이번 문제는 ARM 아키텍쳐 기반으로 구성된 문제다.

ARM 기반의 어셈블리어가 낯선 것을 제외하면 어려운 난이도는 아니었다.


그럼 문제를 푸는데 필요한 사전 지식을 최소한으로 설명하고 문제풀이를 진행하겠당.

(관심이 있으신 분들은 추가로 검색해보시는게 좋을거에요!!)




- ARM 설명 부분 -


Registers

R0 ~ R3 : 함수 호출 인자 전달

R0 ~ R12 : 범용 레지스터

R0 : 함수 리턴 값 저장

R13(Stack Pointer) : Stack Pointer

R14(Link Register) : Return address , 모드에 종속적임

R15(Porgram Counter) : Instruction Pointer

CPSR(Program Status Register) : 최근에 실행된 ALU 연산에 대한 정보를 관리하기 위함


Conditions


Instruction




- 문제풀이 부분 - 


항상 해왔던 것처럼 문제에 포함되어 있던 파일들을 확인해보자. 

"HateIntel"파일과 "ReadMe" 파일이 사이좋게 있는 것을 볼 수 있다. 



읽어달라는 파일을 한번 읽어보자. 

이젠 그렇게 큰 기대는 안한다. 나름 익숙해졌나보다. 캌ㅋ카카ㅏ



지령은 패스워드를 찾아라!! 


오케이 접수했다. 하지만 나는 인텔 아키텍처 기반 OS 밖에 가지고 있지 않는다.

이 문제 때문에 이미지를 구하기도 귀찮고 해서 이번판은 디스어셈블러만 확인하여 문제를 풀어보도록 하겠다. 고로, 동작한 캡쳐는 존재하지 않는다.


편리하게 접근하기 위해 문자열 검색부터 해보았다. 


직관적이고 흥미로운 문자열이었다. 흐흐




그 부분으로 들어가서 분석해보기로 하자. 



대충 보니 어떤식으로 화면에 구성될 지 딱 보이지 않는가 ? 간단하니까~ 음하하

Anyway, 간단히 설명을 하자면 


1. CLI 화면에 "Input Key : " 라는 문자열을 출력한다.

2. 사용자의 입력 값을 받는다. 

3. 함수를 호출한다. 


사실 이 이상 설명할 것도 없다.


이 문제에서 나름 핵심이라 할 수 있는 sub_232c 함수를 미리 설명해보자면,

사용자가 입력한 값을 왼쪽으로 쉬프트하고 그 값으로 원본 값을 덮어쓴다. 



위에서 설명한 sub_232c 함수 호출문 중에 나름 핵심 처리 부분이다. 

내가 입력한 문자열 중 한 문자씩 가지고 와 sub_2494 함수로 전달하면 sub_2494 함수는 이를 왼쪽으로 1씩 (<<1) 쉬프트 연산을 진행한다(흐름으로 본다면 Shift란 표현보단 Rotate가 적당하겠다). sub_2494 함수의 역할은 이게 전부니 더 이상의 설명은 안하겠다. 


이러한 쉬프트 연산을 문자열의 각 글자별로 진행하고 입력된 문자수만큼 진행한다. 


이와 같은 연산이 완료되면 함수는 종료되고 메인 구문으로 복귀한다. 



복귀하고 나면 연산을 거친 문자열과 data 세그먼트에 존재하는 문자열과 비교를 시작한다. 이후엔 머 조건을 만족시키면 미션 완료다. 그래서 난 data 세그먼트에 존재하는 문자열을 긁어와서 위에서 진행한 연산을 반대로 진행하는 코딩을 간단히 짜서 동작시켰다. 

(하나하나 해보려했는디 그게 더 시간이 많이 걸릴거 같아서리...)


어째든 미션 성공~!!









:
Posted by einai
2017. 7. 7. 10:25

[문제풀이] reversing.kr - Twist1 Wargames/reversing.kr2017. 7. 7. 10:25

이번엔 Twist1 문제에 대한 풀이를 진행해보겠다.

이 문제는 다행스럽게도 실행 파일과 텍스트 파일이 같이 존재하고 있었다.



어떤 힌트일까라는 부푼 마음으로 텍스트 파일을 열어보았다.



이 실행파일이 x86 윈도우에서 동작한다는 메시지를 주고 있었다.

너무 친절해서 잠시 당황했었다.

(초보자를 배려해줍시당 ㅠㅠ)


어째든 위 메시지를 본 뒤 실행파일을 동작시켜 보았다.


커맨드 창에서 입력 값을 받아 이를 비교하는 프로그램 같았다.

디버거를 켜고 동작시켜 보았다.



음.. 정상적으로 동작하지 않는다.

그래서 실행 파일을 패킹 탐지 프로그램으로 확인해보았다.



음 뭐가 많이 나왔다. 사실 머가 먼지 정확히는 몰랐다. 걍 대충 어떻겠구나 감만 좀 왔다.

그래서 분석을 해보기로 마음 먹었다.


우선 이 프로그램에는 몇 개의 안티 디버깅 기법이 적용되어 있다.

힙 관련 정보를 이용한 안티 디버깅 기법과 ZwQueryInformationProcess 함수 이용 기법, 컨텍스트 정보를 이용한 Hwbp 확인 기법이다.


우선 흐름을 따라 진행을 해보면 힙 관련 정보를 이용한 안티 디버깅 기법이다.

유저모드에서 FS 레지스터는 TEB를 가리키고 있는데 아래 캡쳐에서 보이는 FS:[30]는 PEB 정보를 가리키는 값을 가지고 있다.



위 캡쳐에서는 PEB 정보를 가지고 와서 최종적으로 PEB+0x18 위치의 값을 가지고 오는데 이는 프로세스 힙 포인터이다. 프로세스 힙 정보를 가지고 함수를 호출하게 되는데 이 함수에서 디버거를 탐지한다.



위 캡쳐는 함수 내부인데 간단히 말하자면 Windows Vista 이전 버전과 이후 버전의 Flags 값을 확인하여 디버거가 프로세스에 붙어 있는지를 검증하는 것이다. 위와 같은 안티 디버깅 적용 방식 때문에 ReadMe.txt 파일에 그와 같은 메시지가 적혀 있었던 것 같다(64비트는 Flags 위치가 다름).



위 탐지 로직을 우회해 계속 진행하다보면 한번 더 힙을 이용한 디버깅 탐지 로직이 존재한다.



위 캡쳐에서 빨간색으로 네모로 표시한 부분이 그 검증 로직인데 프로세스에 디버거가 붙음으로 인해 HEAP_TAIL_CHECKING_ENABLED 플래그와 HEAP_FREE_CHECKING_ENABLED 플래그가 설정되어 생성되는 값을 확인하는 로직이다.


이 부분을 우회하면 그리고 그리던 OEP가 나타나게 된다. 짠!@



이 지점에서 덤프를 뜬 뒤 IAT를 수정해주면 앞으로 분석을 좀 더 수월하게 진행할 수 있다. 그 부분은 별도로 추가하지 않겠다.


쭉쭉 진행하다보면 ntdll.dll에서 ZwQueryInformationProcess 함수 주소를 얻어와 이를 이용해 디버거를 탐지하려 한다.



해당 함수의 두번째 인자로 다른 두 값을 준 뒤 응답 값을 비교하는 식으로 진행하게 된다.

인자로 전달되는 값은 ProcessDebugPort, ProcessDebugObjectHandle 값에 해당되고 이를 이용하여 프로세스 디버깅 포트와 디버깅 객체를 확인할 수 있다.


그리고 마지막 디버거 탐지 로직은 컨텍스트 정보를 얻어와 하드웨어 브레이크포인트 설정 여부를 확인하는 것이다.

이제 거의 막바지당 !!!



위는 GetThreadContext 함수를 이용하여 하드웨어 BP 정보를 얻어온다. 그 뒤 이를 확인하여 하드웨어 BP가 설정되어 있을 경우 예외를 발생시키도록 유도한다.


이를 우회하면 드디어 INPUT 값에 입력한 값을 검사하기 시작한다. 검사는 문자 단위로 이루어지며 쉬프트 연산과 XOR 연산을 이용해 진행한다. 이 과정은 생략하도록 하겠다.



이 문제는 그냥 눈으로만 훑어봤던 안티 디버깅 우회 기법과 언패킹을 시도해볼 수 있는 좋은 기회였다. 출제자님 감사합니당.



:
Posted by einai

이번 문제도 역시 아무런 힌트가 없었다.


문제를 실행시켜서 버튼을 눌러보니 아래와 같이 동작했따.



그래서 올리디버거를 켜서 분석을 진행했다.

가장 만만한 문자열 검색을 시작했고 어렵지 않게 발견할 수 있었다.

위 메시지 뿐만 아니라 조건문도 쉽게 발견할 수 있었다.



간단히 설명하면 비트맵의 래스터 데이터를 메모리로 불러와서 리소스 섹션에 있는 값이랑 비교하여 동일할 경우 승리하는 ... 뭐 그런 문제다.


이 문제 역시 처음엔 멍청한 짓을 하며 시간을 보냈다.

메모리로 복사해 온 데이터란 걸 인지하기 전에 조건문을 만족시키기 급급하여 인라인 패칭을 하여 리소스 섹션에 있는 값을 메모리로 다 복사했었다. 이렇게 하면 화면에 보이는 비트맵에 정답이 보일 줄 알았다.


이같은 짓을 몇 번이나 해본 뒤 내가 얼마나 바보같은 짓을 시도했는지 깨닫게 되었다.


그래서 변경한 방법은 리소스 섹션에 존재하는 내용을 복사하여 그림판으로 열어보는 것이었다. 그래서 API 정보를 확인하고 관련 정보를 수집했다.



GetDIBits 함수에서 사용하는 BITMAPINFOHEADER 구조체를 활용하여 관련 정보를 수집할 수 있다. 


출처 : https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx


이 문제에서 신경써야하는 변수명은 biWidth, biHeight, biBitCount, biSizeImage 정도이다.

이는 순서대로 넓이, 높이, 적용된 비트수, 이미지 크기를 나타낸다.




따라서 리소스 섹션의 래스터 데이터 영역을 바이너리로 복사한 뒤 그림판으로 위 구조체가 가리키는 정보대로 생성한 다음에 비트맵 데이터 영역에  덮어써주면 답이 나온다.



처음에 위와 같은 생각을 하고 그림판에 저장을 했는데 아래와 같은 그림이 나와서 내 접근법이 잘못된 줄 알았다(한 곳에 글자가 뭉쳐저서 이상한 그림처럼 나옴).




답을 알고보니 저렇게 뭉쳐서 나와도 답처럼 보이네.. 그래서 모자이크 ...ㅋ


어째든 시간만 엄청 잡아먹고 성취감도 떨어지는 문제였다.

그러나 뭐 누굴 탓하나.. 미숙한 내 잘못이지 제길!!ㅋ


:
Posted by einai