종종 프로세스의 메모리를 덤프해야될때가 있는데, 이 프로그램은 특정 프로세스의 COMMIT && READ 가능한 영역은 모두다 찾아서 덤프해줍니다. 참고로 유저모드 프로그램이며, 커널 영역으로는 내려가지 않습니다.
(커널에서 후킹이 이루어지는 프로세스인 경우, (ex. 자가보호)  덤프가 안될수 있음)
잘못된 점이 있으면 알려주세요 !





#include <stdio.h>
#include <Windows.h>
#include <Tlhelp32.h>
#include <tchar.h>


//to set super privilege for current process
VOID SetSuperPrivilege(IN LPCTSTR PrivilegeName)
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tp;

//get token handle from current process
if ( !OpenProcessToken( 
GetCurrentProcess(), 
TOKEN_ADJUST_PRIVILEGES, 
&hToken)
) {
_tprintf(_T("OPToken error. %d\n"), GetLastError());
return;
}
__try {


//query debug privilege
if ( !LookupPrivilegeValue(
NULL, 
PrivilegeName, 
&tp.Privileges[0].Luid)
) {
_tprintf(_T("LUPPrivilege error. %d\n"), GetLastError());
return;
}


tp.PrivilegeCount = 1; //must be 1
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //privilege enabled


//adjust token privilege
if ( !AdjustTokenPrivileges(
hToken, 
FALSE, 
&tp, 
sizeof(TOKEN_PRIVILEGES), 
NULL, 
NULL)
) {
_tprintf(_T("ADJUPrivilege error. %d\n"), GetLastError());
return;
}

}
__finally {
CloseHandle(hToken);
}
}


//Enum process list on display
BOOL EnumerateProcessList(VOID)
{
HANDLE hSnapShot = INVALID_HANDLE_VALUE;
PROCESSENTRY32 pe32;

//get a snapshot handle
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if ( hSnapShot == INVALID_HANDLE_VALUE ) {
_tprintf(_T("CTHelp32 error. %d\n"), GetLastError());
return FALSE;
}

__try {

//initialize PROCESSENTRY structure
ZeroMemory(&pe32, sizeof(PROCESSENTRY32));
pe32.dwSize = sizeof(PROCESSENTRY32);

//call first
if ( !Process32First(hSnapShot, &pe32) ) {
_tprintf(_T("PE32First error. %d\n"), GetLastError());
return FALSE;
}

//call next until ERROR_FILE_NOT_FOUND or failed to call next
while( Process32Next(hSnapShot, &pe32) ) {

if ( GetLastError() == ERROR_FILE_NOT_FOUND ) {
break;
}

//Enum process list on display
_tprintf(
_T("%-30s\t\t%-4d\n"), 
pe32.szExeFile, 
pe32.th32ProcessID
);

}

return TRUE;

}
__finally {
CloseHandle(hSnapShot);
}

}

//dump memory which is on target process
VOID DumpAllMemory(IN HANDLE hProcess)
{
HANDLE hFile;
LPVOID lpMem, lpBuffer;
DWORD NumberofBytesWritten;
TCHAR szFileName[MAX_PATH];
SYSTEM_INFO si;
MEMORY_BASIC_INFORMATION mbi;

if ( hProcess == NULL ) {
_tprintf(_T("hProcess is an invalid value.\n"));
return;
}


/* Get maximum address range from system info */
GetSystemInfo(&si);
//initialize MBI
ZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
lpMem = NULL;

while (lpMem < si.lpMaximumApplicationAddress) {
if ( !VirtualQueryEx(
hProcess, 
lpMem, 
&mbi, 
sizeof(MEMORY_BASIC_INFORMATION)) 
) {

_tprintf(_T("VQuery failed. %d\n"), GetLastError());
CloseHandle(hProcess);
return;

}

/* Increase lpMem to next region of memory */
lpMem = (PVOID)( ( (DWORD_PTR)mbi.BaseAddress + 
(DWORD_PTR)mbi.RegionSize) );


if ( (mbi.BaseAddress != NULL) &&
(mbi.State == MEM_COMMIT) ) {


switch (mbi.Protect)
{
case PAGE_EXECUTE_READ:
case PAGE_EXECUTE_READWRITE:
case PAGE_EXECUTE_WRITECOPY:
case PAGE_READONLY:
case PAGE_READWRITE:
case PAGE_WRITECOPY:

//allocate temp buffer to save data
lpBuffer = VirtualAlloc(
NULL, 
mbi.RegionSize, 
MEM_COMMIT, 
PAGE_READWRITE
);

//read data from target process's memory, data is gonna be saved into lpBuffer
if ( !ReadProcessMemory(
hProcess, 
mbi.BaseAddress, 
lpBuffer, 
mbi.RegionSize, 
NULL) 
) {
_tprintf(_T("ReadMemory failed. %d\n"), GetLastError());
VirtualFree(lpBuffer, mbi.RegionSize, MEM_FREE);
break;
}
//generate file name
_stprintf_s(
szFileName, 
sizeof(szFileName), 
_T("%X - %X.dmp"), 
mbi.BaseAddress, 
((DWORD_PTR)mbi.BaseAddress + (DWORD_PTR)mbi.RegionSize)
);

//create file
hFile = CreateFile(
szFileName, 
GENERIC_WRITE, 
0, 
NULL, 
CREATE_ALWAYS, 
FILE_ATTRIBUTE_NORMAL, 
NULL
);

//write data into file
if ( WriteFile(
hFile, 
lpBuffer, 
(DWORD_PTR)mbi.RegionSize, 
&NumberofBytesWritten, 
NULL) 
) {
_tprintf(_T("Dumped successfully : %s\n"), szFileName);
} else _tprintf(_T("failed to dump : %s,  %x\n"), szFileName, GetLastError());

//return resources
VirtualFree(lpBuffer, mbi.RegionSize, MEM_FREE);
CloseHandle(hFile);
break;

default:
break;
}


}


}

CloseHandle(hProcess);
return;
}


int _tmain( int argc, TCHAR* argv[] )
{
DWORD target_pid;

//obtain super privilege
SetSuperPrivilege(SE_DEBUG_NAME);

//enum process list on display
if ( !EnumerateProcessList() ) {
return EXIT_FAILURE;
}

//input target PID
_tprintf(_T("\n\n ### Choose target PID : "));
_tscanf(_T("%d"), &target_pid);

//dump
DumpAllMemory ( 
OpenProcess(
PROCESS_ALL_ACCESS, 
FALSE, 
target_pid
);

//end
system("pause");
return EXIT_SUCCESS;
}
저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
by Sone 2012.01.19 02:44
Named-mutant를 이용한 다중실행 방지 기법은 , 이미 지겹도록 다루어졌고 널리 퍼졌기때문에
이번엔 다른 커널 객체를 이용한 방법을 간단히 다루고자 한다.

결론부터 말하면, 별거없고 그냥 다른 커널객체를 이용할 뿐이다.

바로 소스를 살펴보면,

NTSTATUS ntRet = STATUS_SUCCESS;
HANDLE hSection;
UNICODE_STRING SectionName;
OBJECT_ATTRIBUTES SectionAttributes;
LARGE_INTEGER SectionSize;
CHAR Dbgmsg[100];

RtlInitUnicodeString(&SectionName, L"\\BaseNamedObjects\\s0neSectionObject");
InitializeObjectAttributes(&SectionAttributes, &SectionName, OBJ_OPENIF, NULL, NULL);
SectionSize.QuadPart = 0x1000;   //optional

ntRet = ZwOpenSection(&hSection, SECTION_ALL_ACCESS, &SectionAttributes);

//Is named-section already exist?
if( NT_SUCCESS(ntRet) )
{
ZwClose(hSection);
sprintf_s(Dbgmsg, sizeof(Dbgmsg), "Application is already running. (0x%08X)", ntRet);
MessageBoxA(GetForegroundWindow(), Dbgmsg, "Error", MB_OK);
return EXIT_SUCCESS;
}
else
{
//Create new named-section.
ntRet = ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &SectionAttributes, &SectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);

if( !NT_SUCCESS(ntRet) )
{
sprintf_s(Dbgmsg, sizeof(Dbgmsg), "Section create failed. (0x%08X)", ntRet);
MessageBoxA(GetForegroundWindow(), Dbgmsg, "Error", MB_OK);
return EXIT_FAILURE;
}


//.....continue execution......
         }


먼저 특정 이름의 섹션이 존재하는지 확인한 뒤, 존재한다면 이미 실행중이라 판단하고 종료하고, 
존재하지 않는다면 실행중이지 않다고 판단해서 고유의 이름을 가진 섹션을 새로 생성한다.
사람들이 거의다 뮤텍스만 사용하기때문에, 섹션은 조금 생소할수도 있으나,
따지고보면 결국은 이름 지정이 가능한 다른 커널 객체를 이용한다고 볼수있다.

VS2010 빌드

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
by Sone 2011.02.27 10:25

 
Apple | iPhone 3GS | Normal program | Spot | 1/10sec | F/2.8 | 3.9mm | ISO-1000 | No flash function | 2011:01:25 15:12:01
전 사실 이 책이 2009년에 나온지도 전혀 모르고 있었습니다 -_-;;
어찌보면 당연할수도 있는것이, 국내에 출간되지 않은 책이지요...
가지고 계시는분도 본적도 없고, 구매하셨다는분도 못들어봤구요...


 

Apple | iPhone 3GS | Normal program | Spot | 1/40sec | F/2.8 | 3.9mm | ISO-80 | No flash function | 2011:01:25 15:14:53
책 내용을 살펴보면 자세한 소스코드와 함께, 바로바로 실습할 수 있게끔 설명도 잘되어져 있고 내용 완성도가 매우 높아보입니다.
해외 온라인 평가를 살펴봐도, 아주 좋다는 응답이 많습니다.





Apple | iPhone 3GS | Normal program | Spot | 1/15sec | F/2.8 | 3.9mm | ISO-64 | No flash function | 2011:01:25 18:07:57
이 책을 읽음으로써 배울수 있게되는 내용들이 뒷면에 적혀져 있네요.
저도 아직 모르는것들이 많아서, 다른 서적들과 병행해서 차근차근 읽어볼 계획입니다..
이 책은  멀티프로세서 시스템과 , 윈도우 비스타의 커널 구조를 다룬다는것이 이전 루트킷 서적과 비교했을때 가장 큰 특징이라고 생각됩니다.




Apple | iPhone 3GS | Normal program | Spot | 1/10sec | F/2.8 | 3.9mm | ISO-1000 | No flash function | 2011:01:25 18:27:49

책 사이즈가 생각보다 아담하네요..
두께는 두껍지만(908페이지) 폭이 넓지가 않아서 휴대하는데 생각보다 간편할듯 합니다.



 

Apple | iPhone 3GS | Normal program | Average | 1/12sec | F/2.8 | 3.9mm | ISO-640 | No flash function | 2011:01:25 18:29:21

루트킷 서적과 사이즈 비교한 모습입니다.
실제로 보면 더 작아보입니다.

전 사실 이 책에 대한 첫 인상이, 표지에 한자가 써져있길래 속칭 짱깨 서적인줄 알았습니다....
어쨌든 좋은책인것은 분명합니다.
국내에도 빨리 정식출간 됐으면 좋겠네요.

이 책에 관해서 자세히 알아보시려면
구글에서 The Rootkit Arsenal - Escape and Evasion in the Dark Corners of the System
이라고 치면, 구글 도서 검색결과가 나오는데 거기 들어가시면 목차와 세세한 내용들이 나옵니다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
by Sone 2011.01.25 20:20
| 1 |

티스토리 툴바