336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

간단한 코드를 테스트하려고 VS.NET으로 작성한 MFC가 다른 VS.NET이 설치되지 않은 컴퓨터에서 작동하지 않는다.
라이브러리를 복사해도 마찬가지고...


혹은 msvcr80.dll 를 찾을수 없다는 에러가 난다면...

해결방법 :
1. VS.NET용 라이브러리
릴리즈 버전은
C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86
디버그 버전은
C:\Program Files\Microsoft Visual Studio 8\VC\redist\Debug_NonRedist
에서 CRT, MFC, ATL에 맞는 dll을 실행파일과 같은 경로명에 복사해주면 된다.
(Microsoft.VC80.*.manifest 도 포함해서)

2. C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\vcredist_x86 또는
http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&DisplayLang=ko

자신에 맞는(x86등등) 것을 다운받아서 설치하면 된다.


원인 :
Windows XP에서는 DLL Hell[각주]새로운 프로그램을 설치할때 다른 프로그램이 사용하는 DLL을 덮어 쓰거나 혹은 버전의 불일치로 오는 문제로 기존의 프로그램들이 제대로 동작하지 않는 경우가 있다.[/각주]을 빠져나가려고 Side-by-Side Assembly라는 개념을 만들었다. 이건 여러 버전의 DLL을 동시에 시스템에 존재할 수 있게 해주고, DLL을 사용하는 응용프로그램이 원하는 DLL 버전을 골라서 쓸 수 있도록 해주는 방법이다.
SideBySideAssembly 의 강력한 점은 응용프로그램에서 직,간접적으로 로드하는 모든 DLL이 이 설정의 영향을 받는다는 것이다. 이전에는 응용프로그램이 로드한 DLL에 의해서 간접적으로 로드되는 DLL을 제어할 수 있는 방법이 없었다.

이러한 새로운 방식으로 기존방식대로 VS.NET 라이브러리를 복사하는것으로 끝나지 않고 배포를 위한 별도의 작업이 필요하게 된다.

문제 해결에 대한 페이지
http://www.serious-code.net/moin.cgi/RedistributingVisualCppRunTimeLibrary
http://www.codeproject.com/cpp/vcredists_x86.asp
http://cafe.naver.com/solidcode.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=8

DLL hell에 대해 설명한 페이지
http://www.blogin.com/blog/main.php?datX=00693597&keyZ=x8G3zrHXt6G51iDGwQ==

마이크로소프트사의 side by side assemblies에 대한 설명한 페이지
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sbscs/setup/side_by_side_assemblies.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwxp/html/sidexsidewinxp.asp

블로그 이미지

뚱땡이 우주인

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

먼저 원작자의 자료 : http://www.reversecore.com 에서 참고 했으며 Jeffrey Ritcher 의 Windows 책을 많이 참고 하였습니다. 

DLL  Injection에 대해 알아보겠습니다. 이글을 쓰는 목적은 보안 회사에서 개발자로 있다 보니 많이 접하게 되고 또 리버스 엔지니어링에 관심도 있고 해서 정리 해두고 자 함입니다. 물론 많은 부분을 이 싸이트에서 참고 하였지만 이렇게 정리 하니 다 제것이 되네요 ^^ 

DLL Injection에 대한 의미를 알아 보겠습니다. 

(1) 의미 : 다른 프로세스로 하여금 LoadLibrary API 를 강제로 호출하도록 명령하여 내가 원하는 DLL를 Loading 시키는 것을 의미하며, 일반적인 DLL Loading 과 다른 점은 일반적인 DLL Loading은 자신의 프로세스에 DLL을 Loading 하는 반면DLL Injection의 경우는 다른 프로세스에 DLL를 Loading 시키는 것입니다.

여기서 중요한것은 다른 프로세스로 하여금 자신이 원하는 DLL를 강제로 LoadLibrary 하도록 한다는 점입니다. 이렇게 삽입된 DLL를 해당 프로세스(즉 타겟이 되는 프로세스)의 메모리에 대한 접근 권한을 가지기 때문에 실제로 사용자가 원하는 다양한 일을 할수 있습니다.

 (2) 용도

      1) 악성 코드로서의 일 - 정상적인 프로세스(Winlogon.exe, explorer.exe)에 몰래 숨어 다양한 나쁜짓을 할수가 있습니다.

      2) 기능 개선 및 버그패치 - 어떤 프로그램에 Plug in 개념으로 붙어 기능개선이 가능하며 문제있는 코드, 데이타를 수정할수가 있습니다.

 

실제로 어떤 역할을 수행하는 dll, 즉 사용자가 어떤 기능을 넣은 dll이 있어야 겠고, 또한 그 dll을 inject 시켜줄 exe가 있어야 겠습니다.

실제로 exe 프로그램에서 dll을 inject하는 방법을 자세히 알아보겠습니다.

 

(3) DLL Injection를 구현하는 방법입니다.

     

      1) 가장 일반적인 방법으로 Jeffrey Ritcher 가 제안한 CreateRemoteThread API를 이용하는 방법입니다.

             a. 대상 프로세스(타겟이 되는)의 프로세스 핸들을 구합니다.

                     hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);

            

             b. 대상프로세스(타겟이 되는)의 메모리에 Injection시킬 DLL경로를 써줍니다. 

                    (쉬어가는 고개)

                    원래 Windows 구조상 메모리는 프로세스당 4GB의 독립적인 가상메모리를 갖으며, 이는 서로에게 침범을 받지 않도록

                    독립적인 형태로 구성 되어 있습니다. 그런데 예외적으로 Windows 운영체제는 Debug API를 제공하여 다른 프로세스의

                    메모리 공간에 접근 할수 있도록 하였습니다. 대표적인 API가 이곳에서 쓰게될 VirtualAllocEx(), VirtualFreeEx()

                    WriteProcessMemory(), ReadProcessMemory()입니다.

                   

                    다시 본문으로 돌아와서 대상 프로세스의 메모리에 Injection 시킬 DLL경로를 써줍니다.

                    그러기 위해서는 대상 프로세스의 메모리공간을 DLL 파일 문자열 크기 경로(NULL 포함)만큼 할당합니다.

                     =>

                     LPVOID pRemoteBuf;

                     pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

 

                     할당받은 대상 프로세스의 메모리 공간(pRemoteBuf)에 DLL 경로 문자열을 써줍니다.

                     =>

                     WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDLLName, dwBufSize, NULL);

  

             c. LoadLibrary API 주소를 가져옵니다.

 

                     왜냐하면 실제로 대상 프로세스로 하여금 LoadLibrary 하게 위해서는 LoadLibrary API 주소가 필요로하기 때문입니다.

 

                     HANDLE hMod;

                     hMod= GetModuleHandle("Kernel32.dll");

                  

                     pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");

                     실제로 pThreadProc, 4바이트주소가 필요하다는 의미입니다.

                     그런데 여기서 짚고 넘어 가야할 점이 있습니다.

                     우리가 알고자 하는 LoadLibrary API의 함수 시작 주소는 실제로 대상 프로세스(타겟이되는)의 함수 주소입니다.

                     그런데 위에서 말씀드린 소스는 실제 자신의 프로세스의 LoadLibrary 시작 주소입니다. 먼가 이상하지 않나여?

                     비밀은 여기에 있습니다.

                     실제로 대상 프로세스와 실제 자신의 프로세스의 LoadLibrary 시작 주소가 같다면 문제가 없을 것입니다.

 

                     일반적인 DLL 파일의 ImageBase는 0x1000000000으로 설정되어 있으며, 이미 로딩된 DLL 파일의 주소공간을

                     다른 프로세스도 함께 공유 하게 됩니다. DLL 주소 공간 공유 에대해서는 제 블로그를 한번 찾아 보시면 나옵니다.

 

                     DLL Injection 개념은 위와 같이 OS의 핵심 DLL들이 자신만의 고유한 주소에 로딩되는 것을 보장해주는 Windows

                     특성을 이용한 것입니다.

              

            d. 이제 대상이 되는 프로세스(타겟 프로세스)로 하여금 LoadLibrary하도록 하는 코드만 있으면 끝입니다.

              

                찾아보니 CreateRemoteThread() API 가 있네요. 이 CreateRemoteThread()라는 API는 다른 프로세스에게 쓰레드를

                실행시키라고 명령하는 함수입니다.

 

                여기서 우리가 할일은 원래의 CreateRemoteThread API는 다른 프로세스에게 쓰레드를 실행시켜주는 함수지만 쓰레드

                실행이 아닌 아까 구한 LoadLibrary 함수를 호출하도록 하는 것입니다.

                이것이 가능한 이유는 쓰레드 함수와 LoadLibrary 함수의 매개변수와 리턴값이 4바이트로 모두 같은이유입니다.

 

                       DWORD WINAPI ThreadProc(_in LPVOID lpParameter);

 

                       DWORD WINAPI LoadLibrary(_in LPCTSTR lpFileName);

 

               각 API 함수 원형을 보면 바로 알수 잇죠??

 

               이제 준비가 완료 되었습니다. 호출해줍시다.

               hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);

               WaitForSingleObject( hThread, INFINITE);

 

               이렇게 되면 CreateRemoteThread는 실제로 대상 프로세스의 쓰레드를 실행 시킨것이 아니라 LoadLibrary 를 호출해

               준셈이 됩니다.

 

     2) 두번째 방법으로는 Windows 운영체제에서 기본적으로 제공하는 제공하는 레지스트리 키중에 APPInit_DLLs라는 것이 있습니다.

         여기에 자신이 Injection 시킬 DLL를 써주면 모든 프로세스에 해당 DLL를 알아서 Injection 시켜 줍니다.

         너무 강력하지만 레지스트리 키만 삭제 해버리면 무용지물이 되겠죠??  그래서 잘 사용하지 않습니다.

 

    3) 세번째로 SetWindowsHookEx() API를 이용하여 메시지 훅을 설치하면 OS에서 hook Procedure를 담당하고 있는 DLL를 윈도우를 가진 프로세스에 강제로 인젝션시켜 줍니다.

         실제로 우리 회사(보안회사임)에서 SetWindowsHookEx를 이용하여 메시지 훅을 설치하여 윈도우를 가진 해킹 프로그램을

         실제로 차단하는 소스가 있었습니다(실제로 안쓰지만 ^^)

 

         훅 프로시져를 담당하고 있는 DLL에서(해당 해킹프로그램에 로드) 그 해킹 프로그램의 binary 값과 정책 binary 값과 비교하여 동일하면 그 프로세스를 강제 종료시키는 코드 였습니다.

  

     4) 지금까지는 실제로 실행중인 프로세스에 강제로 Injection시키는 방법이었습니다. 이번에는 대상 프로그램 파일

        자체를 수정하여 DLL를 강제로 로딩하는 방법입니다. 일종의 Crack으로 DLL Injection 하는 과정이 별도로 필요 없습니다.

           파일 자체를 한번 수정하면 DLL Injection하는 과정이 별도로 필요없습니다.

           실제로 notepad.exe 실행 파일에 dll를 로딩시켜 보겠습니다. notepad.exe 파일이 생성될때 자동으로 DLL를 로딩하기 위해서는

           PE Header의 IMPORT DIRECTORY TABLE(IDT)에  DLL를 Import 하도록 추가해야 합니다.

           이과정은 다음 블로그에 올리 도록 하겠습니다. 

 

 

이제 DLL 을 Ejection 시키는 방법에 대해 알아보겠습니다. Injection 시키는 방법과 똑같습니다.

너무 성의가 없었나여?? 대상 프로세스(타겟이 되는 프로세스)로 하여금 FreeLibrary API를 호출하게 하면 됩니다.

 

(쉬어 가는 고개)

Windows Kernel Object에게는 Reference Count라고 하는 참조 카운트가 있습니다. LoadLibrary API를 10번 호출해주면

참조카운트가 10이되고 나중에 해제할때 FreeLibrary를 10번 호출해줌으로써 참조 카운트를 0으로 만들어 주어야 합니다

출처 : http://blog.naver.com/kkan22/80104819805

'ⓟrogramming > Programming' 카테고리의 다른 글

Processes VS Threads  (0) 2018.01.23
ASN.1  (0) 2010.11.04
블로그 이미지

뚱땡이 우주인

,
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

기술연구소 개발1팀 이행렬 과장입니다.

이번에 서울시청에서 AutoServerUpdate.exe가 메모리를 점진적으로 증가시켜 결국에는 Dump를 발생하고

죽는 현상이 있어서 버그를 수정하다가 알아두면 좋은 팁이 하나 있어 소개 드립니다.

기존에 아셧던 분들도 많이 계시겠지만 실제로 실무에서 사용하시면 도움이 될것 같아 보냅니다.


프로그램 개발하면서 메모리 누수가 발생하는 경우 소스 코드를 뒤져가면서 new / malloc / delete 구문을

일일이 찾아가면서 해제 되지 않아 누수가 발생할 곳을 직접 찾는 경우가 많습니다.

그렇지 않은 경우 Windbg 패키지에서 제공된 GFlags.exe 툴을 이용하여 설정한후 덤프가 발생한 경우

잘못된 포인터 사용등을 확인 하는경우가 많습니다.

위에 예시된 방법을 사용하지 않고 메모리 누수를 찾는 방법이 있어 소개해 드립니다.

1) UMDH Tool(Windbg 패키지에 포함됨) 을 이용하여 메모리 누수를 탐지하는 방법

2) LeakDiag Tool을 이용하여 메모리 누수를 탐지하는 방법

이 있는데, 혹자는 LeakDiag Tool 을 이용 하여 메모리 누수를 탐지하는 방법이 좋다고 하는데 그부분은

나중에 확인해보시면 되고 여기서는 UMDH  Tool를 사용하여 찾는 방법입니다.

ms 에서 나와 있는 내용 이므로 링크된 주소를 보시면 더 자세히 알수 있습니다

http://support.microsoft.com/kb/268343/ko


1. UMDH 유틸리티를 설치합니다.(Windbg 패키지에 포함됨)

2. UMDH를 설치한 폴더가 포함되도록 PATH 시스템 환경 변수를 설정합니다.

3. UMDH가 심볼파일을 찾을 수 있도록 _NT_SYMBOL_PATH 환경 변수를 Microsoft 기본 Symbol를 설정합니다.

다음처럼 _NT_SYMBOL_PATH = SRV*c:\symbols*http://msdl.microsoft.com/download/symbols;c:\AutoServerUpdate.pdb

시스템 환경 변수를 설정해주고,

C:\Program Files\Debugging Tools for Windows (x86)>gflags -i AutoServerUpdate.exe +ust

=>AutoServerUpdate.exe의 힙 내용을 덤프하려는 경우 먼저 테스트할 응용 프로그램에 대해 스택 추적 획득을 설정해야 합니다

작업관리자에서 PID를 찾을 수 있습니다.

방금 시작한 AutoServerUpdate 프로세스의 PID가 124라고 가정할 경우 UMDH를 다음 명령과 함께 사용하여 힙 덤프를 얻을 수 있습니다.

umdh -p:124 -f:AutoServerUpdateBefore.log


그리고 메모리가 계속 누수 되는 시점에서 다음 명령을 다시 해줍니다.

umdh -p:124 -f:AutoServerUpdateAfter.log


UMDH 로그 파일(AutoServerUpdateBefore.log / AutoServerUpdateAfter.log)에 프로세스의 현재 힙 상태에 대한 중요한 정보가 포함되어 있지만,

 메모리 누수를 찾으려는 경우 두 로그의 출력을 비교하고 두 덤프 파일 사이에 어떤 호출 스택이 가장 크게 늘어났는지 알아내는 것이 더 유용할 수 있습니다.

Umdh.exe 유틸리티는 두 UMDH 로그를 비교하여 이들 사이의 차이점 분석을 제공하는 데 도움이 됩니다. 다른 간격으로 두 로그를 캡처한 후에 다음 명령을 사용하면 됩니다.

umdh AutoServerUpdateBefore.log AutoServerUpdateAfter.log > result.txt

출력된 result.txt 파일을 열어 어떤 호출 스택이 가장 크게 늘어 나고 해제 되지 않았는지 확인(이 파일에는 해제되지 않은 메모리 할당 횟수/ 바이트가 표시됨) 함으로써

그 때의 콜스택을 보고 소스를 보면  메모리 누수를 금방 찾을수 있습니다.

이상입니다

출처 : http://blog.naver.com/kkan22/80098424440

블로그 이미지

뚱땡이 우주인

,