지난번 iOS Hooking관련 포스팅을 진행하면서 Frida를 소개해드린 바 있습니다.

[링크] http://bachs.tistory.com/entry/iOS-Hooking2Frida?category=892887


전에 언급했던 것처럼 Frida는 iOS뿐만아니라 Android와 Windows에서도 활용할 수 있는데요, 오늘은 Windows에서 활용하는 방법에 대해서 

포스팅을 해보려고 합니다. 예제는 코드엔진의 Basic level03 문제를 이용하였습니다.

[링크] http://codeengn.com/challenges/basic/03


1. 분석

예제 프로그램을 실행하면, 영어인듯 하지만 영어는 아닌것으로 보이는 알럿이 뜹니다.


 

여기서 취소를 누르면 그대로 프로그램을 종료되고, 확인을 누르면 진행이 됩니다.





위의 알럿창에서 뭐라고 이야기했는지 정확히는 모르지만 실행결과를 보니 Regcode를 입력해서 인증을 하는 프로그램인듯 합니다.

더불어 이 예제의 목적은 Regcode를 모르는 상태에서 이 프로그램을 크래킹해내는 것이겠죠.


여기까지를 보고 예상해볼 수 있는 점은 입력 기대값이 있고, 입력값과 비교해서 성공/실패여부를 반환할 것이라는걸 알 수 있습니다.

그리고 이 예제 프로그램이 통신을 하지 않는 것으로 보이니 파일안에 입력 기대값이 존재하거나 로컬에 존재하는 어떤 파일안에 존재할 가능성 등을 

생각해 볼 수 있습니다.  


자세한 건 IDA로 열어서 imports subview를 한번 봅시다.



보다시피 MSVBVM50이라는 라이브러리에서만 참조하는 것으로 보이네요. 검색을 해보면 MSVBVM50.dll은 Visual Basic으로 개발된 프로그램이

참조하는 dll이라는 것을 알 수 있습니다. 또한 목록에서 볼때는 일단 fopen같은 함수가 보이지 않으니, 입력 기대값이 실행 바이너리 안에 존재할 가능성이

더 높아졌네요.


입력값과 입력기대값을 비교하기위해 문자열 비교함수를 사용했을 가능성이 크니 해당 함수를 기점으로 분석 포인트를 잡는 것이 좋을 것같습니다.

import 함수 목록 중 __vbaStrCmp를 포인트로 잡아 보겠습니다.



__vbaStrCmp 함수의 레퍼런스를 찾아보니 두 군데가 나오고 있습니다. 위의 화면은 두 곳 중 더 상위주소에 있는 곳으로 이동한 화면입니다.

__vbaStrCmp 함수를 호출하기전에 ebp-58과 "2G83G35Hs2"라는 문자열을 함수의 인자로 사용하기 위해 push해주고 있는 모습입니다.

이 것을 보고  ebp-58에 우리가 입력한 입력값이 존재하고 "2G83G35Hs2"가 입력 기대값임을 알 수 있습니다.



오, 기대 입력 값은 잘 찾은거 같네요! 하지만 이번에는 Windows후킹에대해 포스팅을 하는 거니까 후킹으로 풀어봅시다.

일단, 우리가 후킹을 걸 메서드는 MSVBVM50.dll 의 __vbaStrCmp()이고, 리턴 값을 조작해주면 될거 같아요.


2. 후킹

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from __future__ import print_function
import frida
import sys
 
def on_message(message, data):
    print("[%s] => %s" % (message, data))
 
def main(target_process):
    session = frida.attach(target_process)
    #print([x.name for x in session.enumerate_modules()])
  
    script = session.create_script("""
    var baseAddr = Module.findBaseAddress('MSVBVM50.dll');
    console.log('MSVBVM50.dll baseAddr: ' + baseAddr);
    //"use strict";
    const __vbaStrCmp = Module.findExportByName("MSVBVM50.dll", "__vbaStrCmp");
    Interceptor.attach(__vbaStrCmp, {
        onEnter: function (args) {
            console.log('===============================================================================');
            console.log('[+] Called __vbaStrCmp!! [' + __vbaStrCmp + ']');
            console.log('[+] args[0] = [' + args[0] + ']');
            dumpAddr('args[0]', args[0], 0x16); 
            console.log('[+] args[1] = [' + args[1] + ']');
            dumpAddr('args[1]', args[1], 0x16);
        },
        // When function is finished
        onLeave: function (retval) {
            console.log('===============================================================================');
            
            /*
                It doesn't work !
            console.log('[+] (Origin) Returned from __vbaStrCmp: ' + typeof(retval));
            console.log('[+] (Origin) Returned from __vbaStrCmp: ' + retval);
            retval = 0;
            console.log('[+] (forgery) Returned from __vbaStrCmp: ' + typeof(retval));
            console.log('[+] (forgery) Returned from __vbaStrCmp: ' + retval);
            */

            this.context.eax = 0x0;
            console.log('Context information:');
            console.log('Context  : ' + JSON.stringify(this.context));
            //console.log('Return   : ' + this.returnAddress);
            //console.log('ThreadId : ' + this.threadId);
            //console.log('Depth    : ' + this.depth);
            //console.log('Errornr  : ' + this.err);
            console.log('===============================================================================');
        }
    });
    // Print out data array, which will contain de/encrypted data as output
    function dumpAddr(info, addr, size) {
        if (addr.isNull())
            return;
        console.log('Data dump ' + info + ' :');
        var buf = Memory.readByteArray(addr, size);
        // If you want color magic, set ansi to true
        console.log(hexdump(buf, { offset: 0, length: size, header: true, ansi: false }));
    }
    function resolveAddress(addr) {
        // Enter the base address of dll as seen in your favorite disassembler (here IDA)
        var idaBase = ptr('0x77EC0000');
        // Calculate offset in memory from base address in IDA database 
        var offset = ptr(addr).sub(idaBase);
        // Add current memory base address to offset of function to monitor 
        var result = baseAddr.add(offset); 
        // Write location of function in memory to console
        console.log('[+] New addr=' + result); 
        return result;
    }
""")
 
    script.on('message', on_message)
    script.load()
    print("[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.\n\n")
    sys.stdin.read()
    session.detach()
    
if __name__ == '__main__':
    if len(sys.argv) != 2:
        print("this script needs pid or proc name :(")
        sys.exit(1)
 
    try:
        target_process = int(sys.argv[1])
    except ValueError:
        target_process = sys.argv[1]
    main(target_process)
cs

Frida공식 홈페이지를 방문하면 기본적인 틀에 대한 설명과 예제 코드를 볼 수 있습니다. 저 역시 아래 링크의 폼에서 수정을 하며 완성을 시켰습니다.

[링크] https://www.frida.re/docs/examples/windows/


2-1 후킹 메서드 주소 찾기

먼저, 해당 __vbaStrCmp 메서드 주소를 찾는 방법입니다.

var baseAddr = Module.findBaseAddress('MSVBVM50.dll');

const __vbaStrCmp = Module.findExportByName("MSVBVM50.dll", "__vbaStrCmp");


위 코드를 실행할 때는 python script_name.py [PID] 로 실행하게 됩니다. 프로세스를 타겟팅해서 attach 하는 것이지요

타겟 프로세스에서 로드되어있는 dll의 주소를 찾기 위해서는 findBaseAddress()를 사용하여 찾을 수 있습니다.


그리고 우리가 후킹을 걸기 위해 필요한 함수의 주소는 findExportByName("dll명", "함수명") 으로 찾을 수 있죠

따라서 const __vbaStrCmp = Module.findExportByName("MSVBVM50.dll", "__vbaStrCmp"); 이 코드가 실행되고 나면 __vbaStrCmp의 주소가

변수에 담기게 됩니다.


프로세스 내부에 존재하는 사용자 정의함수 같은 경우에는 var print_log = resolveAddress('0x0043FC34'); 와 같은 형식으로 얻어와야합니다.

resolveAddress()에 IDA에서 확인한 주소 값(sub_xxxxxxxx)을 인자로 전달해주고, resolveAddress함수 안에 idaBase변수에 IDA에서 사용한 베이스 주소를 입력해준 후 사용해야 합니다.


2-2 onEnter

타겟 함수에 제대로 attach가 되었다면 이제 값을 자유롭게 보고, (권한이 허용되는 한)조작할 수 있습니다.

1
2
3
4
5
6
7
8
9
onEnter: function (args) {
            console.log('===============================================================================');
            console.log('[+] Called __vbaStrCmp!! [' + __vbaStrCmp + ']');
            console.log('[+] args[0] = [' + args[0+ ']');
            dumpAddr('args[0]', args[0], 0x16); 
 
            console.log('[+] args[1] = [' + args[1+ ']');
            dumpAddr('args[1]', args[1], 0x16);
}
cs

onEnter에서는 args변수로 함수 인자 값들을 확인해 볼 수 있습니다. 지금은 두 인자 값이 포인터로 전달이 되기 때문에 hexdump를 떠서 

확인해보고있습니다.


2-3 onLeave

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
onLeave: function (retval) {
    console.log('===============================================================================');
            
    /*
    It doesn't work !
    console.log('[+] (Origin) Returned from __vbaStrCmp: ' + typeof(retval));
    console.log('[+] (Origin) Returned from __vbaStrCmp: ' + retval);
    retval = 0;
    console.log('[+] (forgery) Returned from __vbaStrCmp: ' + typeof(retval));
    console.log('[+] (forgery) Returned from __vbaStrCmp: ' + retval);
    */
    this.context.eax = 0x0;
    console.log('Context information:');
    console.log('Context  : ' + JSON.stringify(this.context));
    //console.log('Return   : ' + this.returnAddress);
    //console.log('ThreadId : ' + this.threadId);
    //console.log('Depth    : ' + this.depth);
    //console.log('Errornr  : ' + this.err);
    console.log('===============================================================================');
}
cs

__vbaStrCmp는 문자열 비교 결과 일치하는 경우 0을 리턴하고 다른경우 -1을 리턴하는 것으로 보입니다.

따라서 1차 적으로는 retval 을 0 으로 만들어 주었었는데요, 확인을 해보니 retval이 바뀌었지만 제대로 동작하지 않는 모습을 보였습니다.

왜인지는 모르겠어요ㅠㅠ


이후에 함수의 리턴값을 저장하는 eax의 값을 확인해보니 0xffffffff로 -1이 저장되고 있는 것을 확인하였고, 

this.context.eax = 0x0; 로 eax값을 0으로 만들어 준 후 정상적으로 크래킹된 것을 볼 수 있었습니다.



끗!

'Study > Windows' 카테고리의 다른 글

CVE-2017-8464 One Day분석 - 1  (0) 2019.03.24

안녕하세요! 벌써 두 번째 책 후기 포스팅을 남기게 되었네요.

이번에 포스팅 할 책은 지난 번 포스팅에 이어 채사장님의 책 우리는 언젠가 만난다 입니다.





1. 계기

읽게된 계기는 역시 채사장님의 신간이기 때문에 집어든 이유가 가장 컸지요. 지금까지 읽어본 채사장님의 책들 모두 마음에 들었었고

때문에 이번에 나온 신간도 마음에 들 거란 기대감에요.


개인적으로 채사장님이 지금까지 쓰신 책들을 크게 두 부류(?)로 나누어 본다면 전에 포스팅 했던 시민의 교양과 같은 사회에 대한 내용에 대해 서술한 부분에 한 부류, 다른 한 부류는 오늘 포스팅 할 우리는 언젠가 만난다, 바로 전에 출간하신 열한 계단과 같은 자아와 세계에 대해 쓴 부류 이렇게 두 가지가 있는 것 같아요. 전 개인적으로 사회에 대해 관심이 많아 전자는 이미 관심이 있는 상태였고 후자는 채사장님의 책들을 읽으면서 생각해보게 되었고 또 재미를 느끼게 된 거 같아요. 


2. 내용

책은 겉 표지에 써져있는 대로 나와 타인 그리고 나와 세계가 어떤 관계를 맺고 있는지 또한 어떤 방식으로 소통하고 있는 지에 대해 이야기를 해주고 있습니다. 그리고 종국에는 책의 제목처럼 우리는 언젠가 만난다 라는 이야기로 끝을 맺지요.


이 책에서 제가 인상 깊었던 이야기를 몇 가지만 또 뽑아볼까 합니다.


- 소년병의 이야기

소년병의 이야기는 나와 타인의 관계에 대한 부분을 풀어 낸 이야기입니다. 개인적으로 이 이야기가 채사장님이 직접 쓰신 부분인지, 아니면 다른 곳에서 인용하신 지는 잘 모르겠으나 정말 마음에 드는 이야기였습니다.


나와 타인이 맺는 관계 특히나 연인 관계에서 누구나 한번 쯤은 해봤음 직한 실수들에 대해 엮어 놓은 느낌이랄까요. 

소년병과 어느 오두막을 지키고 있는 여인이 만들어내는 이 이야기는 만남부터 헤어짐 그리고 그 후까지 생각해보게 만듭니다.



- 낡은 벤치를 지키는 두 명의 군인 이야기

세계와 나의 관계에 대한 이야기 중 등장하는 이 이야기는 관례와 관습에 대해 생각해보게끔 이끌어주는 이야기입니다.

저 역시 마찬가지이고 많은 사람들이 잘 모르는 어떤 일을 할 때엔 앞 사람이 처리 해왔던 대로 똑같이 하려고 하는 경향이 강할 것이라고 생각합니다.

잘 모르는 상태로 위험을 감수하기 보다는 관례와 관습에 따라 안전한 길을 선택하는 것이죠. 하지만 이 에피소드를 읽고나면 이런 선택에 대해 다시 생각해 볼 수 있을 거라고 생각합니다. 


이 부분을 다 읽고 내가 소중히 지키고 있는 것들 중에 낡은 벤치가 있지는 않을까 하고 생각해보았습니다.



 - 결론을 향하여

부제 그대로 결론을 도출해 나갑니다. 우리가 왜 언젠가 만나게 되는지...

채사장님이 나는 누구인가, 세계는 무엇인가, 우리는 왜 존재하는가 에 대해 논리적으로 풀어낸 이 내용들과 과정들이 너무 재미있어서 

뽑아봤습니다. 또한 전에 들어본 적도 없고 제가 고려해보지 못한 관점이기 때문에 신선했습니다.


이 책의 결론대로라면 제목처럼 우리는 언젠가 만납니다. 각자의 여행을 마치고 만날 우리는 어떤 모습으로 만나게 될까요?


3. 마무리

책을 다 읽고 마지막 장을 덮었을 때, 나중에 다시 보고싶은 책이 있습니다.

책이 나에게 해주고 싶은 이야기가 있는 것 같은데 내가 아직 그 이야기를 들을 준비가 되어 있지 않아서 온전히 이해 못하는 것 같은 느낌이 드는 책이 

그렇습니다.


우리는 언젠가 만난다고 이야기하고 있는 이 책 역시 저에게 더 많은 이야기를 전달해주려고 했지만 이번에는 다 못들은 느낌이네요. 

나중에 이야기를 들을 준비가 되었다고 생각이 들 때, 다시 읽어 보고 싶은 책입니다.

 

'일상 > BooK' 카테고리의 다른 글

라틴어 수업 - 나는 공부하는 노동자입니다.  (0) 2018.03.22
죄와 벌  (0) 2018.02.26
시민의 교양  (1) 2018.01.11

올해다짐했던 책리뷰 포스팅을 처음으로 시도해봅니다. 처음이니만큼 글의 구성을 어떻게 해야할 지 막막하지만.. 

늘 그랬듯이 써지는대로, 그냥 마음대로 써보려고 합니다. 책리뷰 그 첫 번째 책은 채사장님의 시민의 교양입니다.


1. 읽게된 계기..

팟캐스트 "지적 대화를 위한 넓고 얕은 지식" 을 즐겨 들으며 자연스레 채사장님을 알게 되었습니다. 제목처럼 다양한 지식들을 얕게 한번 파보는 

팟캐스트인데요, 이 내용들을 정리한 책도 있답니다.


저는 두 책 중에 왼쪽에 있는 1편밖에 읽어보지 못했습니다. 역사, 경제, 정치, 사회, 윤리에 대해 말하고 있는 이 책은 이해하기 쉽도록 

구성이 되어있습니다. 적절한 예시와 단순한 설명으로 정말 마음에 들었던 책이였죠. 


이후 채사장님이 쓰신 책들은 다 읽어볼 가치가 있겠다 싶어 그즈음 신간이였던 "열한 계단"을 읽었고 자연스럽게 '시민의 교양도 꼭 읽어봐야지' 라는 

생각이 들어 읽어보게 되었습니다.  이 글을 쓰는 지금은 "우리는 언젠가 만난다" 를 읽고 있는 중입니다. 아마 다음 포스팅 책이 되지 않을까 하고 

생각하고 있습니다.


2. 내용

사회는 굉장히 복잡한 이해관계 속에서 다양한 상황이 일어나기 때문에 쉽게 이해 할 수 없습니다. 이러한 이해관계는 어떻게 발생하였으며 

어떤식으로 드러나게 될까요? 아마 이 책을 읽기 전이었다면 추상적이고 두루뭉술한 이야기를 하였거나, 잘 모르겠다. 라는 대답을 했을 것 같습니다.


이 책은 세금, 국가, 자유, 직업, 교육, 정의, 미래의 카테고리를 가지고 세상을 보다 단순하게 바라볼 수 있는 시야를 가지게 해주었습니다. 그리고 언론 혹은 정치인들이 사용하던 어휘나 말들의 참 뜻에 대해서 조금은 이해 할 수 있게 된 것 같습니다. 

가장 인상 깊었던 카테고리를 두 가지 정도 뽑아보자면 바로 직업교육입니다.


- 직업

세상에 수 많은 직업이 있지만 이 책에서는 단 네 가지로 나누어 설명해줍니다. 


투자가, 자본가, 비임금노동자, 임금노동자


각 직업이 어떻게 발생을 하였는 지 어떤면에서 유리하고 어떤 부분에서 불리한 지에 대해 역시 단순한 예시와 쉬운 설명으로 이해를 도와줍니다.

이 카테고리가 인상깊었던 이유는 도입부에 있습니다. 비서실장과 시민의 대화에서 직업의 본질에 대해서 이야기 하는 부분이였는데요, 


시민은 직업을 선택 할 때 흔히 잘하는 일 혹은 좋아하는 일에 따라 고민을 한다라고 생각하지만 "산업화 사회에서 그런건 없다." 라고 이야기 합니다. 

그리고 이어서 "운동화 생산라인에서 일하는 사람은 좋아하는 일을 선택한 것입니까 잘하는 일을 선택한 것입니까?" 라는 질문을 던집니다. 


이 문장을 읽고 정말 많은 생각을 하게 되었습니다. 그리곤 직업이란 개념에 대해서 내가 뭔가를 놓치고 있구나 라고 생각하게 되었죠. 

요즘은 잘 모르겠습니다만, 제가 초등학교에 다니던 시절 학교에서 직업에 대해서 설명할 때 크게 두 가지 의미를 갖는다고 배웠던 것 같습니다. 


소득. 

자아실현의 의미.


오늘 날 구조에서 과연 직업이 저러한 의미를 갖는가? 에 대해 진지하게 고민을 하게되었습니다.


- 교육

교육 카테고리에서는 무엇을 어떻게 가르칠 것인가? 에 대한 내용을 다룹니다. 그리고 덴마크의 교육제도에 대해 설명한 부분도 재미있게 읽었습니다. 

여기서 인상 깊었던 점은 경쟁의 정당성에 대해 이야기 한 부분입니다. 우리나라는 교육을 통해 경쟁이 자연스럽게 학습되고 그 결과를 받아들이는 것 또한 정당한 것으로 학습시킵니다. 결과적으로 사회의 구조적인 문제로 발생한 문제 또한 경쟁에서 밀려났기때문이라고 생각하게끔 만들죠.


우리나라 내신제도에서 중간 정도 등수를 기록한 학생은 내신 5등급을 받게 됩니다. 내신 5등급을 받은 학생은 흔히들 이야기하는 sky를 포함한 "인서울"로 표현되는 대학들을 가지 못하게됩니다. 그리고 그 영향을 받아 취업경쟁에서도 대기업을 가기 힘들어집니다.

우리나라 경제인구를 100명으로 줄을 세웠을 때 경제소득순위 50등에 있는 사람의 연봉은 1074만원으로 한달에 90만원 정도가 됩니다. 물론 내신 5등급을 받은 학생이 반드시 연봉 1074만원을 받게되는 것은 아니겠지만, 분명 큰 영향을 받게 되는 것은 인정할 수 밖에 없죠.


이 책과 같이 제가 말하고자 하는 것은 중간정도의 노력을 한 사람이 중간정도의 소득을 얻지 못하는 현상은 사회의 문제로 봐야할 것이지 당연히 경쟁에서 밀렸기 때문으로 치부할 수 없다는 것입니다. 이러한 문제에 대해 여러분은 어떻게 생각하시나요?


3. 마무리..

이 책을 읽기 전과 후 사회를 보는 시야가 많이 바뀐 것 같다고 스스로 생각이 듭니다. 비교적 좀 더 단순하게 보고 이해하게 될 수 있게 되었으며, 

생각해 볼 거리가 많이 늘어났습니다. 세금, 국가, 자유, 직업, 교육, 정의, 미래에 대해 막연하고 어렵게 느껴지신다면 

꼭 한번 읽어 보셨으면 좋겠습니다.


쉽고 간단하게 그러나 중요한 것은 놓치지 않는 선에서 잘 설명을 해놓은 책이니까요. 


'일상 > BooK' 카테고리의 다른 글

라틴어 수업 - 나는 공부하는 노동자입니다.  (0) 2018.03.22
죄와 벌  (0) 2018.02.26
우리는 언젠가 만난다.  (0) 2018.01.15

+ Recent posts