강지윤
강지윤

Reputation: 1

How to Load PE Files for Process Hollowing?

The target is notepad.exe

The code to insert is a PE file called Hello.

PE FILE:

Error:

error occurred --> if (IDH->e_magic== IMAGE_DOS_SIGNATURE
error content is "Exception through: read access violation. IDH was 0xC4."

The following is the whole code.

    #include <Windows.h>
    #include <TlHelp32.h>
    #include <stdio.h>
    #include <tchar.h>
    #include <string.h>
    #include <stdlib.h>
    #include <string>
    #include <tchar.h>
    #include <locale.h>


    #define FILE_PATH ("C:/Windows/System32/notepad.exe")
    #define PE_FILE_PATH ("C:/Users/code1/Desktop/Hello.exe")


    typedef LONG(WINAPI* NtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);

    void ProcHollowing(LPSTR szFilePath, PVOID ); //pFile);
    PVOID pFile();

    int main(){
        ProcHollowing((LPSTR)(FILE_PATH), pFile());

        return 0;
    }

    PVOID pFile() { //PE파일의 DATA 추출 부분 (.text 추출)
        HANDLE hFile = CreateFile((LPCWSTR)PE_FILE_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);

    if (hFile == INVALID_HANDLE_VALUE) {
        printf("Fail: Hello.exe 파일이 없습니다.");
    }

    return hFile;
    }

    void ProcHollowing(LPSTR szFilePath /*TargetProc*/, PVOID pFile/*PE Data*/) {
    PIMAGE_DOS_HEADER IDH;/*PE 구조의 첫 시작부분 DOS 헤더*/
    PIMAGE_NT_HEADERS INH;/*PE헤더*/
    PIMAGE_SECTION_HEADER ISH; //섹션 헤더
    PROCESS_INFORMATION PI; //프로세스 정보
    STARTUPINFOA SI; //생성시 프로세스에 대한 윈도우 스테이션, 데스크탑, 표준 핸들 및 주 창의 모양을 지정하는 구조체.
    PCONTEXT CTX;
    PDWORD dwImageBase; //생성된 프로세스의 Image Base 주소
    NtUnmapViewOfSection NewNtUnmapViewOfSection;
    LPVOID pImageBase;
    int Count;

    IDH = PIMAGE_DOS_HEADER(pFile);

    if (IDH->e_magic== IMAGE_DOS_SIGNATURE/*PE 파일이 맞는지 시그니처를 통해 확인한다.*/) { //IMAGE_DOS_SIGNATURE는 4D5A 즉 MZ
        _tprintf(TEXT("SUCCESS: This is PE File\n"));
        INH = PIMAGE_NT_HEADERS(DWORD(pFile) + IDH->e_lfanew); // Dos header의 끝부분 + 시작 부분으로 PE Header를 구하는 것.

        if (INH->Signature == IMAGE_NT_SIGNATURE/*시그니처 확인하여 PE포멧 파일인지 구분*/) {
            _tprintf(TEXT("SUCCESS: PE FILE Check\n"));

            RtlZeroMemory(&SI, sizeof(SI)); // SI의 크기만큼 0으로 채워준다는 의미. 즉, 초기화
            RtlZeroMemory(&PI, sizeof(PI));
            bool bResult = CreateProcessA(szFilePath/*실행할 모듈의 이름 notepad.exe*/, NULL, NULL, NULL,
                FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI); // 정상 프로세스를 생성. SUSPENDED 상태.

            if (bResult) {//프로세스가 잘 생성되면
                _tprintf(TEXT("SUCCESS: CreateProcessA\n"));

                CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); //CTX 가상 메모리 할당.
                CTX->ContextFlags = CONTEXT_FULL; //Context 구조에서 초기화해야하는 부분을 나타내는 값.

                if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))/*프로세스 정보 획득*/) {
                    ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&dwImageBase), 4, NULL); /*Image Base 주소 구하기*/
                    //ebx에는 PEB 주소가 들어가 있고 PEB+8에는 Image Base 주소가 들어가있다. 
                    //PEB(Process Environment Block)에는 해당 프로세스에 대한 정보가 들어가있음.
                    _tprintf(TEXT("SUCCESS: Get Image Base Address\n"));

                    if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase) { //Image Base와 PE Header의 OPTIONAL HEADER의 Image Base가 같으면
                        NewNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"),
                            "NtUnmapViewOfSection")); //메모리 할당해지 핸들이랑 주소
                        _tprintf(TEXT("SUCCESS: Unmap\n"));
                        NewNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase)); //정상 프로세스의 메모리 할당 해지
                    }
                    else {
                        _tprintf(TEXT("FAIL: Unmap\n"));
                    }

                    pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(INH->OptionalHeader.ImageBase), //재할당
                        INH->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);

                    /*악성코드 데이터 삽입 부분 같은데 여기부분 이해 잘 안됨.*/
                    if (pImageBase) { //재할당 완료 되면
                        _tprintf(TEXT("SUCCESS: Reassignment\n"));
                        WriteProcessMemory(PI.hProcess, pImageBase, pFile,/*pFile, 즉 데이터를 넣어주는 부분같음.*/
                            INH->OptionalHeader.SizeOfHeaders, NULL);//악성코드 삽입(?) 헤더를 바꿔주는 거같음.

                        for (Count = 0; Count < INH->FileHeader.NumberOfSections; Count++) {
                            ISH = PIMAGE_SECTION_HEADER(DWORD(pFile) + IDH->e_lfanew + 248 + (Count * 40));

                            WriteProcessMemory(PI.hProcess,
                                LPVOID(DWORD(pImageBase) + ISH->VirtualAddress),
                                LPVOID(DWORD(pFile) + ISH->PointerToRawData),
                                ISH->SizeOfRawData, NULL);
                        }
                        WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),// 메모리 쓰기. Image Base
                            LPVOID(&INH->OptionalHeader.ImageBase),
                            4, NULL);

                        CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint; //AddressOfEntryPoint는 PE파일이 메모리에 
                        //로드된 후 맨 처음 실행되어야 하는 코드의 주소가 포함되어 있음.
                        //Eax는 Original Entry Point(OEP)가 들어가 있음. 즉, 실행 프로그램의 실제 시작 위치
                        SetThreadContext(PI.hThread, LPCONTEXT(CTX)); //프로세스 정보 변경
                        ResumeThread(PI.hThread); //프로세스 재실행
                    }
                    else {
                        _tprintf(TEXT("FAIL: Reassignment\n"));
                    }
                }
                else {
                    _tprintf(TEXT("FAIL: Get Image Base Address\n"));
                }
            }
            else {
                _tprintf(TEXT("FAIL: CreateProcessA\n"));
            }

        }
        else {
            _tprintf(TEXT("FAIL: PE FILE Check\n"));
        }
        VirtualFree(pFile, 0, MEM_RELEASE);
    }
    else {  //PE파일이 아니면 
        _tprintf(TEXT("FAIL: This is not PE File\n"));
    }
}

Upvotes: 0

Views: 569

Answers (1)

orca.eaa5a
orca.eaa5a

Reputation: 11

There are too many things to fix for excution

I will not upload the modified code because there are some parts that were not implemented..

First,

PVOID pFile(){ // hFile is a HANDLE but ret type is PVOID... hmmm
...
    //HANDLE hFile = CreateFile((LPCWSTR)PE_FILE_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0); // <-- GENREIC_WRITE? and CREATE_ALWAYS?
    HANDLE hFile = CreateFile($file_name, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
...

You should read MSDN Docs CreateFile You create a file handle, but there is no reading method (like API ReadFile) ^ This is the cause of the error.

...
if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase) {
NewNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"),
    "NtUnmapViewOfSection"));
NewNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase)); 
...
...
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),
                        LPVOID(&INH->OptionalHeader.ImageBase),
                        4, NULL);
...

STUDY ASRL!

...
CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint; 
                    SetThreadContext(PI.hThread, LPCONTEXT(CTX));
                    ResumeThread(PI.hThread);
...

You ResumeThread before write the Dos Header, Dos Stub, PE Header in child process Memory

you have to fix entire codeㅠㅠ :(

Upvotes: 1

Related Questions