zj3t

email: euntaejang@gmail.com

Latest Posts

Reversing-PE패치를 이용한 DLL로딩

By 오후 11:44 ,

안녕하세요.
오랫만의 포스팅이네요~요즘은 문제만 풀다가 너무 모르는게 많아서
리버싱 핵심원리라는 책으로 공부하고있어서 책으로 하는동안은 실습해 볼 수 있는것만 간단히 포스팅 하겠습니다.

이번 포스팅은 PE파일을 중요성을 알게해주는 내용인것 같습니다.

간단히 설명하자면 DLL을 실행파일에 PE 패치를 통해 인잭션 한다고 보시면 됩니다.
여기서 인젝션 할 DLL파일은 특정 웹 사이트의 index.html 파일을 다운받아서 TextView.exe에 보여줍니다.

리버싱 핵심원리의 아무 처리를 가하지 않은 예제 파일을 작업 폴더로 이동시킵니다.

NULL 패딩 영역입니다. 왜 찾는지는 밑에서 설명하겠습니다. 여기서 우리는 8C80을 시작으로 이용할 것이라고만 말하겠습니다.


IMAGE_OPTIONAL_HEADER의 IMPORT Table 구조체 맴버는 IMPORT Directory Table의 위치와 크기를 알려줍니다.

.rdata 섹션에 있는 IDT를 보면 이렇게 DLL가 나열되어 있습니다. 쉽게보면 이 실행파일에서 사용되는 API가 모아져있는 라이브러리라고 생각하시면 됩니다.

우리는 이 영역을 복사하여 위의 NULL 패딩영역으로 복사하여 새로운 DLL을 그 밑에 추가할 것입니다. 왜 굳이 복사하여 추가하느랴 하면 IDT영역에 새로 DLL을 추가할 공간이 여유롭지 않기 때문에 아무것도 없는 NULL영역으로 복사하여 그 밑에 인젝션할 DLL을 추가 시키고 IDT에 대한 정보를 담고있는 IMPORT Table을 복사한 곳으로 수정 할 것입니다.

저 빨간 네모가 주의 깊게 보셔야 할 부분입니다. HxD(헥스 에디터)에서는 RVA 메모리의 섹션 주소가 아닌 RAW파일의 주소로 나타내어 집니다. 계산법이 따로 있지만 여기서는 따로 쓰지 않겠고 저 왼쪽 위 설정을 바꾸면 파일에서의 주소로 변경 됩니다.

즉 160, HxD로 이동해 보겠습니다.

160 주소로 가보니 리틀엔디안으로 표시되어있지만 위에서본 84CC(RVA), 64(SIZE)가 보입니다. 우리는 이것을 84CC를 8C80으로, 64를 78로 바꾸어 주어여 합니다. 
(!!: 여기서 알고 넘어가야 할 것이 있습니다. IDT(IMPORT Directory Table)은 IID(IMAGE_IMPORT_DESCRIPTOR) 구조체 배열로 이루어져 있습니다. (지금은 PE 구조체를 설명하는 포스팅이 아니기 때문에 이런것이 무엇을 하는 구나만 알고 다음 포스팅에서 제대로 설명하겠습니다.) 여기선 임포트 하는 DLL 파일 하나당 IID 구조체가 하나씩 필요합니다. IID 구조체 하나의 크기는 14바이트입니다.(여기서 DLL을 하나 인잭션하는 것이 목표이기 때문에 구조체를 하나 더 추가시켜서 64->78로 바꾸는 것입니다.)


자 이렇게 IMPORT Table을 값을 바꾸었습니다.

이제는 원래의 IMPORT Table의 값을 복사하여 아까 찾은 NULL부분에 복사해야합니다. 
84CC~852F는 RAW로는 76CC-772F범위에 있습니다. 이것을 복사하여 새로운위치 84CC 즉 RAW로 7E80에 붙여 넣기 할 것입니다. 

이렇게 복사가 끝났습니다. 이제는 DLL을 추가하는 작업을 해야합니다.
우리가 추가할 DLL파일의 이름은 (myhack3.dll이란 이름을 가진 DLL 파일입니다.)

여기서부터 조금 복잡해 집니다. 저도 책을 몇번을 돌려봤었습니다. 제가 이해한대로 작성할테니 혹시 아니거나 이상한 부분이면 쪽지나 댓글 부탁드리겠습니다.

일단 보고 가야할 것이 있습니다. IID구조체의 코드를 보고 가겠습니다.

typedef struct_IMAGE_IMPORT_DESCRIPTOR{
    union{
         DWORD Characteristics;
         DWORD OriginalFirstThunk;  //RVA to INT
    };
    DWORD TimeDateStamp;
    DWORD ForwarderChain;
    DWORD Name;                     //RVA to DLL Name
    DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;    //RVA ro IAT

아까 DLL을 하나 추가할 때마다 IID 구조체 하나가 추가된다고 했었습니다.
여기서 중요한 부분은 저 주석처리한 부분입니다. IAT는 아시다 시피 IMPORT Address Table입니다. 어떤라이브러리에서 어떤 함수를 사용하고 있는지 기술한 테이블입니다. INT는 IMPORT Name Table이라고 위에 부분의 이름을 가지고 있는 테이블이라고 이해하시면 쉽습니다.

myhack3.dll이라는 dll파일을 추가시키기 위해 우리는 IID의 변수 부분을 알맞게 고쳐주어야 합니다.

typedef struct_IMAGE_IMPORT_DESCRIPTOR{
    union{
         DWORD Characteristics;  //0
         DWORD OriginalFirstThunk;  //RVA to INT //00008D00
    };
    DWORD TimeDateStamp; //0
    DWORD ForwarderChain; //0
    DWORD Name;                     //RVA to DLL Name   //00008D10
    DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;    //RVA ro IAT  //00008D20

              RVA                         RAW
INT       00008D00                 00007F00
Name    00008D10                 00007F10  
IAT        00008D20                00007F20

IID의 구조체에서 8D00, 8D10, 8D20은 임의로 설정해 준 장소입니다. 아직은 이해안가시 겠지만 끝까지 보시면 이해가 가실거에요.....

우선 새로 추가한 IID 구조체에 값을 써줍니다.

각각 INT, NAME, IAT입니다.

여기서 저도 가장많은 시간 고민했던 부분입니다. 일단 RAW와 RVA가 계속 햇갈렸고 왜 dummy가 뭐길래 INT와 IAT가 모두 저곳을 포인터하나 였습니다. 일단 헷갈리시지 않도록 위에 RVA로도 표현해놨으니 보시는데 큰 어려움은 없으실겁니다. HxD는 모두 RAW로만 표현되서 RVA는 직접구해야 합니다. 다음엔 구하는 방법에 대해 포스팅하겠습니다.

dummy함수에 대해서 알아봤는데 일단 dummy()함수는 myhack.dll 파일에서 외부로 서비스하는 익스포트(Export)함수라고 합니다.

__declspec(dllexport) void dummy()
{
        return0;
}

하지만 보는 바와 같이 아무런 기능이 없습니다. 아무 기능이 없는 함수를 익스포트하는 이유는 myhack3.dll을 TextView.exe 파일(맨첨 작업폴더로 옮긴 실행파일)의 임포트 테이블에 추가시킬 수 있도록 형식적인 완전성을 제공하기 위한 것이라고 합니다. PE파일에서 어떤 DLL을 임포트한다는 것은 파일의 코드 내에서 그 DLL이 제공하는 익스포트 함수를 호출한다는 의미입니다. PE헤더에는 DLL 이름, 함수, 이름등의 정보가 기록되어있는데, 따라서 myhack3.dll 파일은 형식적인 완전성을 위해 익스포트 함수를 최소한 하나 이상 제공해야 하는 것입니다.
-리버싱 핵심원리

여기 이 말을 제 방식대로 정리해봤을 때 
myhack3.dll파일은 형식적인 완전성을 위해 익스포트인 함수 dummy()를 제공해야 했고 PE파일에서 즉 TextVIew에서 myhack3.dll을 임포트한다는 것은 곧 myhack3.dll이 제공하는 익스포트인 함수인 dummy()를 호출한다는 의미라는 거죠 그래서 INT와 IAT가 dummy()를 가리키고 있었던 것 같습니다.

이제 거의다 끝났습니다. 간단한 한 가지가 남아있습니다.
IAT는 PE로더에 의해서 메모리에 로딩될 때 실제 함수 주소로 덮어쓰기 때문에 해당 섹션은 반드시 WRITE 속성을 가지고 있어야 합니다. 그래야 PE로더가 정상적으로 쓸 수 있기 때문입니다.
PEView로 .rdata 섹션 헤더를 보면 

이렇게 설정되어있습니다. 우리는 쓰기 속성(80000000)을 주어서 C0000040로 만들어 주어야 합니다. 저기 보니 RAW가 224네요 HxD로 224주소로 가서 수정해주면 될 것 같습니다.

이제 다 끝났습니다. 하지만 여기서 궁금한 것이 있습니다. 맨첨 TextView.exe 파일은 쓰기속성 없이 잘 실행되어있는데 왜 dll을 추가한 지금은 쓰기 속성을 추가해 주어야 하는 것일 까요??

궁금증은 IMAGE_OPTIONAL_HEADER구조체의 Data Directiry배열중 IMPORT Address Table에서 해결할 수 있습니다. 

즉 말하자면, 6000~6154 부분에 IAT가 존재하면 그 섹션에는 쓰기 속성이 없어도 됩니다.

하지만 우리는 새로추가한 DLL을 설정해 주느랴 IAT를 범위 밖에다 지정한 것을 확인할 수가 있었습니다. 따라서 쓰기 속성이 필요하다는 것을 알 수가 있습니다.

이제 모든 것이 끝났습니다. 

정확하게 되었는지 테스트해보겠습니다.

일단은 잘 추가 된 것같습니다. 

INT에도 dummy() 함수가 잘 추가된 모습을 볼 수 있습니다. 일단 외형적으로는 IAT, Import Directory, INT 모두 문제 없어 보입니다. 그럼 이제 내부적으로도 잘 되었는지 실행을 해봐야 할 것 같습니다. 실행은 myhack3.dll파일과 TextView파일을 같은 폴더에 넣고 TextView를 실행하면 됩니다.

위에서 말했든 myhack3.dll파일은 특정 웹 사이트의 index.html 파일을 다운받아서 TextView.exe에 보여줍니다.


자 성공입니다. index.html 파일을 TextView.exe.에 보여주고 있습니다. DLL을 인잭션하기 전에는 아무 것도 뜨지않는 TextView.exe 였습니다.

이렇게 아무것도 띄지 않는 화면입니다. 하지만 저렇게 TextView로 텍스트만 보여주니 성공이 긴가민가 할 수도 있습니다. 이렇게 해볼까요??

자 웹사이트에서 보니 성공임을 바로 알 수 있었습니다. 

process explor로 확인 했을 때도 TextView.exe를 실행했을 때 myhack.dll이 작동하는 것을 확인 할 수 있습니다. 
의심할 수 없는 성공 입니다.

따라하시다 보면 글로만 배우던 PE보다 훨씬더 재미있고 아~이래서 PE가 필요하구나 아실 수 있을 것입니다. 리버싱 핵심원리라는 책을 사고 PE정리를 정말 잘 해놓으셨구나 느낄 수 있었습니다. 이 포스팅은 리버싱 핵심원리에 있는 실습을 해본 후 이해한 뒤 저나름대로 포스팅 했습니다.

여기까지 PE패치를 이용한 DLL 인젝션을 마치도록 하겠습니다. 


여지껏 포스팅하면서 가장 오랜시간 작성한 글인것 같습니다. PE에 대해서는 저도 지금은 배우고 있는 입장이라 이렇게 하나씩 실습, 포스팅하면서 실력을 늘려보겠습니다. 요즘 블로그 조회수가 갑자기 확늘었습니다. 예전에는 저 혼자만 왔다거렸는데 많이 봐주시는 만큼더 신경써서 포스팅하겠습니다. 

 


파일첨부



리버싱 핵심원리의 저자분이 운영하시는 www.reversecore.com에서 다운받은 파일입니다.파일의 저작권 문제가 있다면 바로 삭제하겠습니다.
감사합니다.




You Might Also Like

0 개의 댓글