달력

4

« 2024/4 »

  • 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

이번 문제는 윈도우 커널과 관련있는 문제이다 .


윈도우 커널 쪽 분석은 시도한 적도 없고 굉장히 생소해서 신선한 경험을 해볼 수 있었다. 

이 문제는 키보드를 후킹하는 드라이버 파일을 분석하여 문제를 푸는 것이다. 문제를 푼 지금도 드라이버 동작 과정이나 커널 내부 동작 과정이 정확히는 그려지지 않고 아 이런식으로 동작하겠구나 정도로 겉핥기식 개념만 잡은 것 같다. 이 문제를 계기로 윈도우 커널쪽도 좀 더 공부해봐야 겠다.


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



문제를 다운로드 받아서 풀면 위와 같이 3개의 파일로 구성되어 있다. 

아래는 ReadMe 파일인데 인증을 소문자로 해달라고 부탁하고 있다. 



일단 문제를 동작시켜 보았다. 맨 처음엔 비활성화 된 입력란이었지만 옆에 버튼을 누르면 활성화가 되면서 문자를 입력할 수 있게 변경된다. 문자열을 입력하고 Check를 클릭하면 내가 입력한 값이 맞았는지 틀렸는지 확인할 수 있다. 




우선 WindowsKernel.exe 파일은 SCM을 이용하여 드라이버를 로드시키고 있다. SCM을 이용하면 레지스트리 키가 생성되며 드라이버는 페이징되지 않는다. 아래 캡쳐는 로드되는 부분의  과정 중 일부이다. 



위 과정 중 StartService 함수를 만나면 아래와 같이 드라이버가 로드된다. 이는 Winker.sys 드라이버에 삽입된 디버깅 메시지이다. 



일단 WindowsKernel.exe 에서 DeviceIoControl 함수를 통해 디바이스 드라이버에 IRP 처리를 요청할 수 있다. 드라이버는 특정 IRP 요청에 맞춰 IRP를 처리할 수 있게 설계할 수 있다. 이는 드라이버 오브젝트의 MajorFunction을 수정하는 것으로 가능하다. DeviceIoControl 함수로 IRP 요청을 보낼 경우 IRP_MJ_DEVICE_CONTROL 에 설정된 함수에서 이를 처리하게 된다. 아래 캡쳐는 그 과정을 보여준다. 



위에서는 CREATE, CLOSE, DEVICE_CONTROL과 관련된 Major Function을 초기화해주고 있다. 실제 DEVICE_CONTROL 함수 쪽 내부를 따라 들어가면 몇몇 변수를 초기화해준다. 


그리고 이 문제를 풀기 위해 다른 중요한 개념은 DPC이다. 

원래는 여기에서 주저리 주저리 설명을 하려했는데 지저분하고 흐름을 끊어버리는 것 같아서 다음에 시간을 내서 별도로 작성하도록 하겠다. 



위에 있는 내용은 DPC 객체를 초기화하는 과정이다. EDI 레지스터에 KeInitalizeDpc 함수의 주소가 들어있다. 여기서 설정된 루틴이 이후에 해답을 찾을 때 매우매우 중요한 역할을 한다. 일단 이 부분에서는 초기화만 하고 지나간다. 



이후 흐름을 따라 내려가다보면 다시 한번 DPC 객체를 초기화하고 이를 큐에 삽입한다. 여기서 삽입된 DPC 루틴은 IDT의 키보드 관련 ISR을 후킹한다. 여기까지 왔으면 거의 다 푼거나 마찬가지다. 해당 루틴이 실행되고 나면 아래와 같이 IDT가 변경된다. 



해당 부분을 분석해보면 READ_PORT_UCHAR 함수를 이용하여 키보드가 입력할 때마다 값을 가져오고 이 값을 비교한다. 해당 함수를 통해 입력한 문자를 확인하면 보통 아스키코드 값이랑은 다르다. 어떤 의미인지 정확히는 모르겠지만 이 값을 이용하여 비교문을 잘 통과하면 답을 얻을 수 있다. 






:
Posted by einai

※ LEVEL 13


Q. There is a security check that prevents the program from continuing execution if the user invoking it does not match a specific user id.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
 
#define FAKEUID 1000
 
int main(int argc, char **argv, char **envp)
{
  int c;
  char token[256];
 
  if(getuid() != FAKEUID) {
      printf("Security failure detected. UID %d started us, we expect %d\n", getuid(), FAKEUID);
      printf("The system administrators will be notified of this violation\n");
      exit(EXIT_FAILURE);
  }
 
  // snip, sorry :)
 
  printf("your token is %s\n", token);
  
}
cs


A. 이는 간단한 리버싱 문제이다. "// snip, sorry : )" 라고 표시되어 삭제된 코드 부분을 맞추는 문제이다. 


위의 14번째 라인만 우회하면 토큰 생성 로직으로 넘어가게 되는데 어셈블리어를 스스로 분석해도 되고 그냥 넘어가도 알아서 토큰이 생성되어 출력되므로 뭐 편할대로 하면된다. 간단하니까 별도 설명없이 캡쳐만 첨부하도록 하겠다. 


[그림 1] 로직 우회 후 토큰이 생성되는 것을 확인


[그림 2] 토큰 값을 패스워드로 사용하여 로그인 




※ LEVEL 14


Q. This program resides in /home/flag14/flag14. It encrypts input and writes it to standard output. An encrypted token file is also in that home directory, decrypt it :)


A. 이는 토큰 파일에 암호화되어 있는 문자열을 복호화하는 문제이다. 이 또한 굉장히 단순한 리버싱 문제이다. 


[그림 3] 토큰 값 확인 


[그림 4] 프로그램을 실행하여 암호화 로직 확인 


보는 바와 같이 굉장히 간단한 암호(?)화 방식이다. 실행 방식만 봐도  규칙을 알 수 있다. 문자열 인덱스 값을 문자 아스키코드에 더해 나오는 방식이다. 그럼 뭐 간단히 코드를 짜서 복호화해도 되고 얼마 안되니 수동으로 해도 되고.. 


[그림 5] 토큰 값 확인 


[그림 6] 플래그 확인 



이번 두 문제는 오히려 이전 레벨보다도 너무나 쉬웠다.

이런 문제들도 가끔 나와야지 ~ ㅋ






:
Posted by einai

이 문제는 이전에 MetroApp 문제의 업그레이드 버전이라고 보면 될 것 같다. 


게임으로 동작되는 터라 낯선 부동소수점 연산을 눈에 익히는 과정과 객체를 분석하는 과정에 애를 먹었다. 

낯선 어셈블리 명령어를 보니 문제가 더욱 더 어려워보였다. 


하지만 막상 문제를 풀었을 때는 핵심을 놓치고 주변 것들에 너무 신경을 쓰고 있었구나 라는 느낌을 받았다. 


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

우선 ReadMe.txt 파일을 먼저 열어보았다.




해당 파일을 보았을 때 두개의 플래그가 존재하고 이를 결합한 뒤 md5 해시 함수를 적용하면 되겠구나 싶었다. 물론 정답은 소문자로 입력하고..!!




이후 애플리케이션을 동작시켜 보았다.




짠 ~ 저 네모난 주인공이 빨간 악마를 총으로 쏴 죽이는 게임이다. 


이를 보았을 때 뭐를 어떻게 해야 답을 맞출까 고민을 했다. 게임 난이도는 엄청나게 어렵다.

활성화되어 있는 악마만 죽일 수 있고 속도도 다양하고 움직이는 방향도 다르다. 




쩜쩜쩜.. 마음을 가다듬고 문제를 분석했다. 



저기에 보이는 빨간 박스에 존재하는 게 첫번째 조건이다. 0xDDB 수만큼 악마를 죽이면 된다. 그래도 이건 양호하다.

두번째 조건은 0x31159cd 마리를 잡아야 한다. - - ;


순간 별의별 생각을 다했다. 악마를 일렬로 내려오게 할까? 모든 악마를 활성화 시켜볼까? 등등..

결국 걍 알아서 죽이게끔 만들어서 동작시켰다. 



흠흠.. 게임할 땐 엄청 빨리 내려오던 악마들이 너무 천천히 내려왔다. 물론 속도는 동일하겠지만 스코어가 올라가는걸 보고 있자니 가슴이 답답했다. 약 1시간? 가량 돌리다보니 첫번째 플래그를 얻을 수 있었다. 


1초에 한마리씩이라고 가정했을 때의 속도랑 거의 유사했다. 

이후 고민을 했다. 


0x31159cd 마리는 약 51468749 초가 걸리고... 이는 857812분이 걸리고.. 이는 14296시간이 걸리고.. 이는 595일이 걸린다. 이 문제를 풀기 위해 약 2년이 안되는 시간을 컴퓨터만 켜놓고 요놈만 바라보고 있을 것인지.. 다른 해결책을 찾을 것인지..!!



결국 다른 해결책을 찾았다. !

걍 정답 로직을 구현해서 돌려버렸당. 그러니 뭐 금방 답이 나왔따 ! 냠냠

이제 CRC 문제들만 남았넹.. 아직 머릿속에 그림이 안그려지는디 어떻게 접근해야 할랑가~



:
Posted by einai

이 문제는 윈도우 앱을 리버싱하는 문제이다. 


이 문제 하나로 윈도우 앱 분석을 어떻게 해야하는지 알겠다라고 깨닫긴 힘들었지만

그래도 접근은 어떻게 해야겠다 라는건 알았다. 


나중에 시간이 되면 더 깊게 공부해봐야겠다. 할때마다 느끼지만 참 공부란게 끝도 없다. 

그래서 이쪽 일이 재미있는 거지만 하루가 너무 짧다. 이것만 할수도 없고 ㅠㅠㅠ



푸념은 이정도로 하고 문제풀이 들어가보도록 하겠다. 

문제를 동적으로 풀기 위해서는 윈도우 8 이상 앱이 동작할 수 있는 환경을 깔아줘야 한다. 


일단 문제를 다운받으면 읽어달라는 놈을 읽어보자. 



이 시점에는 저게 먼 의미가 있을랑가 ~ 일단 음 저렇구나 하고 넘어가보자. 


환경이 구축되었으면 앱을 실행시켜보자. 




동작화면은 이렇다. 패스워드를 입력하고 "OK" 버튼을 누르면 뭐 옳다, 그르다 이런 팝업이 뜬다. 


사실 앱을 설치할 때 주의해야 할 사항이 있다. 

인증서가 만료되어 신뢰할 수 없기 때문에 파워쉘을 켜서 날짜를 조절해주고 설치를 시작한다.


또한, 신뢰되지 않은 사용자가 게시한 소프트웨어를 실행하기 위해서는 아래와 같이 설정해줘야한다.  

간단히 명령어만 나열하자면, 

 > Set-ExecutionPolicy -ExecutionPolicy Unrestricted 

 (캡쳐를 안찍었는데 다시 찍기는 귀찮다 ㅠㅠ)


이런 일련의 과정을 겪고 나면 위처럼 정상적으로 실행될 것이다. 



만약!!!!! 이 모든게 귀찮다. 

환경 구성도 귀찮고 다 싫다! 하시는 분은 appx 파일의 확장자를 zip으로 변경한 뒤 압축을 풀면 된다. 




그럼 뙇!! 하고 실행파일이 생기는데 이거를 머 IDA로 열어서 확인해보면 된다. 

얼떨결에 만지다보니 파일 시그니처가 압축 파일인 걸 알아서 풀어보니 걍 저렇게 있었다. 


어째든 실제 동작 로직을 찾아가기 위해서는 동적분석이랑 같이 해주는게 편하다(for me). 

아직 익숙하지 않아서 그냥 찾아가기가 복잡스러워보인다. 



분석해야 하는 함수에 맞딱뜨리면 저렇게 기이이인 뭔가가 보기만해도 짜증나게 나타난다.

근데 사실 분석해야 하는 부분은 극도의 일부이다. 저것까지 알려주면 보시는 분의 재미를 빼앗아가는 것 같아 하지 않겠다.


진행하다보면 눈에 보이는 트릭이 존재하는데 알아서 잘 판단하시길 바란다. 

너무 얽매이지 않기를!!






극도의 일부를 분석하고 나면 답을 구할 수 있다. 답을 구할 때 힌트가 유용할 것이다. :) 





드디어 100위권 진입





:
Posted by einai

이번 문제는 플래쉬에 있는 액션스크립트를 분석해서 문제를 푸는 것이다. 

바로 문제풀이로 들어가보자~!

플래쉬 로더를 이용하여 플래시 파일을 실행시켜보자. 




위에 캡쳐와 같이 그냥 회색 화면에 입력받는 곳이 딸랑 하나 존재한다. 


프레임은 총 7개가 존재했다. 

디컴파일러를 구동시켜 내부를 살펴보도록 하겠다. 

swf 파일 역시 디컴파일러가 존재하여 검색한 뒤 다운받아 실행시켜 보았다. 




대충 위와 같은 구성으로 되어있다. 


내부의 액션스크립트는 음 인터넷으로 검색해서 봤던 거와는 달랐다. 

감이 잘 안와서 아 또 처음부터 차근차근해야하나 싶은 마음이 들었다. 

물론 공부하면야 좋지만,,, 왠지 그닥 관심이 가지 않았다. ㅠㅠ


그래서 스크립트를 걍 훑어보던 중 





위와 같이 전역 함수 gotoAndPlay()를 보게되었다. 다른 조건문에는 포함되지 않았는데 유독 저기에만 있었다. 

그래서 혹시나 싶어 다른 버튼 이벤트도 확인해보았다. 



여기도 존재했다. 각 입력란에 조건에 맞는 값을 넣어주니 정답이 뙇 !!



음 먼가 얻어걸린 느낌이다. 나중에 시간되면 차근차근 공부해봐야지~~ 나ㅏㅏㅏㅏ중에 ..


나중에 검색해서 알아보니 해당 디컴파일러에 난독화 해제 기능도 존재했고 이를 해제하니 완전 간단한 소스가 나왔다. 쩜쩜쩜...


:
Posted by einai

이번 문제는 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

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


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


사실 이 문제보다 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

해당 문제는 간단한 게임으로 만들어진 리버싱 문제다.


나같은 초보자한텐 문제에 대한 힌트가 없는게 참 난감하다.

일단 게임을 동작시켜 보았다.




리버싱의 시작은 스트링 검색!! ㅋㅋ 일단 승리와 관련된 문자열을 검색해보았다.



게임을 깼을 때 화면에 나오는 텍스트 문자열을 얻으면 그게 답이겠거니 감이 왔다. 

현 시점에서 문자열은 의미없는 문자열이다.




다시 게임으로 돌아와 저 악당들을 모두 해치우면 게임이 끝나고 의미없는 문자열이 답으로 변경되겠지 싶었다. 근데 한놈당 8발씩이나 맞춰야 하고 접근하면 에너지가 달아죽었다. 


그래서 게임을 좀 편리하게 두가지 꼼수를 부렸다. 


첫번째 꼼수는 에너지 검증 로직 우회를 통해 죽지 않는 것..!!



아무리 맞아도 죽지 않게 변경하였다. 짠!



두번째 꼼수는 얘들이 너무 많아서 한마리만 탄생시키는 것이었다. 

혼란의 시작은 여기서부터였지...



일단 한마리만 나왔다. 그래서 요놈만 죽이면 끝날 줄 알았다.

하지만 이놈을 죽여도 끝나지 않았다. 이때부터 머리속이 헝클어지면서 착각했던 내용 떄문에 문제의 논질을 찾지 못하고 한참을 헤맸다.


결국 검색의 도움을 조금 받았다. ㅠㅠㅠㅠ

악당 한놈 죽일때마다 한글자씩 변경된다는 것!!

난 악당이 없을 때 이벤트가 발생하며 글자가 변경될 것이라 착각했다.

미숙한 분석 실력과 추측을 기반으로 하다보니 ㅠㅠㅠ 



진즉에 검증 로직은 확인했었는데 내가 악당을 한놈으로 만들어버리니 그 부분이 호출이 거의 안되 이해하는데 난항을 겪었다. 제길 ㅋㅋㅋ 꼼수가 오히려 분석을 어렵게 만든 꼴이 되었다.


위 사실을 확인하고 검증 로직으로 BP를 걸고 악당을 한마리씩 처치해보았다. 




악당 인스턴스의 특정 위치에 있는 값을 가지고 와서 승리시 발생하는 문자열과 XOR 연산을 진행한다. 악당 인스턴스의 특정 위치에 있는 값은 4의 배수이고 악당 인스턴스 순서에 따라 승리시 발생하는 문자열과 연산을 진행한다. 


그래서 승리시 발생하는 문자열을 4의 배수 값과 XOR 연산을 진행하면 정답이 나온다.

첫번째 글자 = (0*4) ^ 첫번째 글자

두번째 글자 = (1*4) ^ 두번째 글자 

....... 



:
Posted by einai