473,325 Members | 2,774 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,325 software developers and data experts.

Injecting Code to an existing PE

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;
}

--
Nadav
http://www.ddevel.com
--
Nadav
http://www.ddevel.com
Nov 17 '05 #1
5 2852
Nadav wrote:
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/is...E/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.

--
Ben
http://bschwehn.de
Nov 17 '05 #2
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)?

"Ben Schwehn" wrote:
Nadav wrote:
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/is...E/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.

--
Ben
http://bschwehn.de

Nov 17 '05 #3
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

Nov 17 '05 #4
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;
}

"Ben Schwehn" wrote:
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? ;)


Nov 17 '05 #5
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
Nov 17 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: George Sakkis | last post by:
Is there a general way of injecting code into a function, typically before and/or after the existing code ? I know that for most purposes, an OO solution, such as the template pattern, is a cleaner...
10
by: Brian W | last post by:
Hi All, I have a web user control that, among other things, provides Print this page, and Email this page functionality I have this script that is to execute on the click of the asp:hyperlinks ...
2
by: Christopher Ambler | last post by:
I'm wondering if there's a solution here - I have an ASPX page with a sole purpose of scaling an image. The ASPX page contains a single line with the codebehind tag, and the .cs file contains...
17
by: Luke Matuszewski | last post by:
Hi ! Simple question (but thus it may appear no simple answer): If i putting a script onto the page i simply could inline it in <script> element or via its src attribute so (second way): <script...
9
by: tai | last post by:
Hi. I'm looking for a way to define a function that's only effective inside specified function. Featurewise, here's what I want to do: bar_plugin_func = function() { ...; setTimeout(...);...
14
by: ofiras | last post by:
Hii everyone, I'm a web programmer, but I never understood sql injecting. All I found was that you can write "a' or 'a'='a" in the password field to try to connect without knowing the password. I...
4
by: Peter Waller | last post by:
Dear Pythoners, I know this will probably be perceived as 'evil voodoo', and fair enough: it probably is. I guess it is unpythonic. ... but I want to know how to do it anyway - mostly for my...
1
by: rh.krish | last post by:
Hi, I have a unique situation. We have many applications (approx - 20) built on .NET framework 1.1 & 2.0 and hosted in one single IIS website in PROD. We have similar setup in TEST. Now we want to...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.