Injecting Code to an existing PE

G

Guest

Hi,

Introduction:
************************************************************
I am working on a project that should encrypt PE files ( Portable executable
), this require me to inject some code to existing PEs.
First, I have tried:
1. to inject some code to the end of the ‘.text’ segment of an existing PE
2. to set the entry point RVA to the address of the injected code
3. at the end of the injected code I have set a jmp to the original entrypoint
The problem:
Opening that file and browsing to the entrypoint address I can see the
injected code BUT when running the application I can see that the IP points
to the correct address ( Base + RVA ) but the injected code is not there (
just some gibberish ), I tried setting the following flags for the section:
‘IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_CNT_CODE |
IMAGE_SCN_CNT_INITIALIZED_DATA’, BUT still, No good, I get the same results…
A .Any comments remarks or pointers will be appreciated.
B. Any pointers to documentation concerning how the PE loader work will be
appreciated ( e.g. which sections are loaded when, … )

************************************************************
Following is the code I use:
HRESULT InjectCode(char *pSourceName, char *pTargetName)
{
DWORD dwBytesRead = 0;
BYTE *pFileMemImage = 0;
LARGE_INTEGER liSourceSize;
HANDLE hSource = CreateFile(pSourceName, GENERIC_READ,
FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(0 == hSource)
return HRESULT_FROM_WIN32(GetLastError());
GetFileSizeEx(hSource, &liSourceSize);
pFileMemImage = new BYTE[(DWORD)liSourceSize.QuadPart];
ReadFile(hSource, pFileMemImage,
(DWORD)liSourceSize.QuadPart,
&dwBytesRead, 0);
CloseHandle(hSource);

IMAGE_DOS_HEADER *pdosHeader = (IMAGE_DOS_HEADER*)pFileMemImage;
IMAGE_NT_HEADERS32 *pNtHdr = (IMAGE_NT_HEADERS32*)(pFileMemImage +
pdosHeader->e_lfanew);
IMAGE_SECTION_HEADER *pSecHeader = (IMAGE_SECTION_HEADER*)((PBYTE)pNtHdr +
sizeof(*pNtHdr));

DWORD dwWrittenBytes = 0;
// Copy the new function to the end of the '.text' segment
BYTE *pInjectedCode = pFileMemImage + pSecHeader[1].PointerToRawData +
pSecHeader[1].Misc.VirtualSize -
sizeof(INJECTED_SEGMENT_LIBLOAD);
DWORD *pJumpAddress = (DWORD*)(pInjectedCode +
sizeof(INJECTED_SEGMENT_LIBLOAD) -
sizeof(DWORD));
memcpy(pInjectedCode, INJECTED_SEGMENT_LIBLOAD,
sizeof(INJECTED_SEGMENT_LIBLOAD));
pSecHeader[1].Characteristics |= IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_CNT_CODE
| IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_LNK_REMOVE;

*pJumpAddress = pNtHdr->OptionalHeader.AddressOfEntryPoint -
(DWORD)((PBYTE)pJumpAddress - 1);

pNtHdr->OptionalHeader.AddressOfEntryPoint = (DWORD)(pInjectedCode -
pFileMemImage);

HANDLE hTarget = CreateFile(pTargetName, GENERIC_WRITE, 0, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
WriteFile(hTarget, pFileMemImage, (DWORD)liSourceSize.QuadPart,
&dwWrittenBytes, 0);
CloseHandle(hTarget);

return S_OK;
}
 
B

Ben Schwehn

Nadav said:
I am working on a project that should encrypt PE files ( Portable executable
), this require me to inject some code to existing PEs.

I believe this is caused by not updating the size of the .text section,
therefore the loader doesn't map your injected code into memory.
http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx

"It's important to note that PE files are not just mapped into memory as
a single memory-mapped file. Instead, the Windows loader looks at the PE
file and decides what portions of the file to map in."

This sems to make sense also because then the section header's
characteristics (IMAGE_SCN_MEM_READ etc) can easily be applied to the
different memory pages.
 
G

Guest

Hi Ben,

Thanks again for your responce, The code I add to the '.text' segment is
added at the end on the existing '.text' segment (the existing segment is not
enlarged) e.g. if the size of the '.text' segment is X i add the code at
[Base + X - 'Size of injected code'] this may override existing data in case
the actual data size is alligned to 0x1000, BUT on first stage I would like
to avoid enlaging the '.text' segment size, after achieving what was just
described I would try to enlarge the .text segment ( changing existing RVAs
and so )..., anyhow, back to the problem, putting the code at the position
just mentioned works fine as long as for the written file, BUT when the
loader load the file it seems the requiered segment is not mapped... I
wonder... why does not all of the '.text' segment is mapped to memory? how
should I configure the PE so it will load all of the '.text' segment... what
flags should I set in addition to the one I have alerady set (see my root
query)?
 
B

Ben Schwehn

You're right of course.

If tried your code with some minor adjustments and the injected code is
there when the PE is executed.
Perhaps you're just looking at the wrong location? ;)

The most significant change i made is

pNtHdr->OptionalHeader.AddressOfEntryPoint =
pSecHeader[0].VirtualAddress - pSecHeader[0].PointerToRawData +
(DWORD)(pInjectedCode - pFileMemImage);

since you have to translate the EntryPoint to a RVA. (pSecHeader[0] ist
the text section header of my test file). Often
pSecHeader[0].VirtualAddress - pSecHeader[0].PointerToRawData is 0 so it
doesn't matter. Don't know if this is causing you're problem...?

Only tested it with injecting 0xc3 (ret) and 0xcc (breakpoint) but that
worked.

ben
 
G

Guest

Hi Ben,

Thanks for your response, Indeed setting the entry point as you have advised
solved the problem, Now I have tried to extend the '.text' segment so
existing data would not be overwritten, to achieve that I have used the
ICeeFileGen interface provided by Microsoft (the app i am injecting
[unmanaged] code to is a managed executable, starting with an unmanaged JMP
_CorExeMain), I have successfully extended the segment and injected my code,
BUT, when setting the entrypoint of the executable to a location other then
it's original position I get 0xC000007B => STATUS_INVALID_IMAGE_FORMAT,
injecting the code without changing the entrypoint causes the PE to execute
normally, using some common PE disassembler ( PE Explorer ) I can see the
modified entrypoint points to the right RVA:
( The injected code is added right after the original code )
jmp_mscoree.dll!_CorExeMain://<==The original entrypoint
jmp [mscoree.dll!_CorExeMain]
;----------------------------------------------------------------------
EntryPoint:// <== the updated entrypoint
push ebp
mov ebp,esp
sub esp,000000FCh
push ebx
push esi
blablabla...

My guess is that additional configuration is needed to be done to the PE
headers so 0xC000007B will not show... what it is... i don't really
know.......

The Injection/entrypoint modification code:
HRESULT AssemblyEmitter::pEWriter::InjectCode()
{
HCEESECTION Section = 0;
HRESULT hr = FileGen->GetSectionCreate(ceeFile,
".text",
0,
&Section);
if(FAILED(hr))
return hr;
char *pCode = 0;
hr = FileGen->GetSectionBlock(Section,
sizeof(INJECTED_SEGMENT_LIBLOAD),
4,
(void**)&pCode);
if(FAILED(hr))
return hr;
memcpy(pCode, INJECTED_SEGMENT_LIBLOAD,
sizeof(INJECTED_SEGMENT_LIBLOAD));
return FileGen->ComputeSectionOffset(Section,
pCode,

&m_pEmitter->m_uiInjectedCodeEntryPoint);
}

HRESULT AssemblyEmitter::pEWriter::UpdateEntryPoint(WCHAR *pSourceName)
{
DWORD dwBytesRead = 0;
BYTE *pFileMemImage = 0;
LARGE_INTEGER liSourceSize;
HANDLE hSource = CreateFile(pSourceName,
GENERIC_READ,
FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(0 == hSource)
return HRESULT_FROM_WIN32(GetLastError());
GetFileSizeEx(hSource, &liSourceSize);
pFileMemImage = new BYTE[(DWORD)liSourceSize.QuadPart];
ReadFile(hSource, pFileMemImage,
(DWORD)liSourceSize.QuadPart,
&dwBytesRead, 0);
CloseHandle(hSource);

IMAGE_DOS_HEADER *pdosHeader = (IMAGE_DOS_HEADER*)pFileMemImage;
IMAGE_NT_HEADERS32 *pNtHdr = (IMAGE_NT_HEADERS32*)(pFileMemImage
+ pdosHeader->e_lfanew);
IMAGE_SECTION_HEADER *pSecHeader = (IMAGE_SECTION_HEADER*)((PBYTE)pNtHdr
+ sizeof(*pNtHdr));
DWORD dwWrittenBytes = 0;
IMAGE_SECTION_HEADER *pSec = 0;
for(int i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++)
{
pSec = pSecHeader + i;
if(0 == strcmp(".text", (char*)pSec->Name))
break;
pSec = 0;
}
if(0 == pSec)
return E_FAIL;
// Copy the new function to the end of the '.text' segment
IMAGE_DATA_DIRECTORY *pdd =
(IMAGE_DATA_DIRECTORY*)pNtHdr->OptionalHeader.DataDirectory
+ IMAGE_DIRECTORY_ENTRY_COMHEADER;
DWORD dwCorhdrOffset = pdd->VirtualAddress
+ pdd->Size
- pSec->VirtualAddress;
BYTE *pInjectedCode = pFileMemImage
+ pSec->PointerToRawData
+ m_pEmitter->m_uiInjectedCodeEntryPoint
+ dwCorhdrOffset;
DWORD *pJumpAddress = (DWORD*)(pInjectedCode
+ sizeof(INJECTED_SEGMENT_LIBLOAD)
- sizeof(DWORD));
// pSec->Characteristics |= 0xc0000040;
DWORD dwOriginalAddress = pNtHdr->OptionalHeader.AddressOfEntryPoint;
pNtHdr->OptionalHeader.AddressOfEntryPoint =
pSec->VirtualAddress
+ m_pEmitter->m_uiInjectedCodeEntryPoint
+ dwCorhdrOffset;
*pJumpAddress = dwOriginalAddress
- (pNtHdr->OptionalHeader.AddressOfEntryPoint
+ sizeof(INJECTED_SEGMENT_LIBLOAD));
DeleteFile(pSourceName);

HANDLE hTarget = CreateFile(pSourceName,
GENERIC_WRITE,
0,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
WriteFile(hTarget,
pFileMemImage,
(DWORD)liSourceSize.QuadPart,
&dwWrittenBytes,
0);
CloseHandle(hTarget);

return S_OK;
}
 
S

Socket

There are a lot of information about PE file structures, loader and so
on, try, for example, http://win32asm.cjb.net/ or if you understand
Russian (http://www.wasm.ru)

If I should implement the similar project, I simplify my task to avoid
Windows PE loader:

1. run PE file as secondary process using CreateProcess with
CREATE_SUSPENDED
flag (may be OR with DEBUG_PROCESS flag too)

2. modify code of already loaded PE file, using WriteProcessMemory

Some other functions should be used as well: OpenProcess and
VirtualProtectEx

Regards:
http://ircdb.org
http://smike.ru
http://xedit.smike.ru
 
Top