Can't find a way to get the ICeeGen interface

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

1. I am writing some kind of a CLI Linker
2. I am using the unmanaged meta-data API.
I wonder browsing "cor.h" I have encountered the 'ICeeGen' this interface is retrieved by the 'ICorModule' interface, I didn't find any API that provide me the means to get an 'ICorModule' interface, how should I get this interface? What object should i create? what method should I call?

Any comments remarks or pointers will be appreciated.
 
1. I am writing some kind of a CLI Linker
2. I am using the unmanaged meta-data API.
I wonder browsing "cor.h" I have encountered the 'ICeeGen' this interface is retrieved by the 'ICorModule' interface, I didn't find any API that provide me the means to get an 'ICorModule' interface, how should I get this interface? What object should i create? what method should I call?

Any comments remarks or pointers will be appreciated.
Hello Nadav

short answer is: call
EXTERN_C HRESULT __stdcall CreateICeeFileGen(ICeeFileGen **ceeFileGen);
exported from mscorpe.dll.

Have a look at ICeeFileGen.h.

I'm currently in the process to make this work myself and will post a
longer answer tomorrow if possible.

hth
 
Hi Ben,

Thanks for your response, 'CreateICeeFileGen' is used to create an
ICeeFileGen Object and NOT ICeeGen Object, ICeeFileGen is used to emit an
assembly to the disk, however usage of this interface require access to data
not exposed by IMetaDataEmit, this require the usage of an additional objects
PELoader, ICeeGen, ... ( objects OTHER THEN ICeeFileGen ), from some
additional research I have done, I have found the sscli ( search through the
inet ) library very useful, it has the source code of the CreateICeeFileGen (
through the CCeeFileGenWriter class ) and have the source code for CCeeGen (
which implements the ICeeGen interface ), all of this and much more is open
source and free of charge...

P.S.
We could discuss these Issues in details through Windows Messenger, you can
find me with the following e-mail address: nadavr AT yahoo DOT com

Nadav.
 
Thanks for your response, 'CreateICeeFileGen' is used to create an
ICeeFileGen Object and NOT ICeeGen Object, ICeeFileGen is used to emit an

oops, sorry, didn't read your posting carefully enough.
assembly to the disk, however usage of this interface require access to data
not exposed by IMetaDataEmit, this require the usage of an additional objects
PELoader, ICeeGen, ... ( objects OTHER THEN ICeeFileGen ),

hmm, why?

Perhaps you're trying to accomplish something different than I do, but I
got the following to work by just using the ICeeFileGen object:

- Open a assembly with IMetaDataEmit, IMetaDataImport etc.
- Create a new Assembly (.exe) with ICeeFileGen, copy the metadata in
it, copy all the IL code of all methods
- save the new file.

this gets me a working executable. Well pretty much at least, for now
I'm still having some problems with exception handling code not being
copied properly and I'm not sure what to do with embeded ressources, so
the PE file does not verify with peverify yet, but simple hello world
stuff is already working

It should he easy changing the IL code, adding new Methods etc. So this
is good enough for me :) and also seems what you're trying to do as
described in your earlier post "Assembly emmition problem"...?
from some
additional research I have done, I have found the sscli ( search through the
inet ) library very useful, it has the source code of the CreateICeeFileGen (
through the CCeeFileGenWriter class ) and have the source code for CCeeGen (
which implements the ICeeGen interface ), all of this and much more is open
source and free of charge...

I was considering going this path as well, one problem I find with this
(other than the sheer inconvenience) is that it's not going to be
updated for new Versions of the frameweok, so I'm not sure if you won't
get into problems when dealing with 2.0 assemblies containing generics
and so on.
Using mscorpe.dll provides you with an up-to-date class. Also the 2.0
version of the ICeeFileGen class has a few new methods that seem worthy
of further exploration like CreateCeeFileEx2 (takes an existing assembly
as a "seed file")
We could discuss these Issues in details through Windows Messenger, you can
find me with the following e-mail address: nadavr AT yahoo DOT com

I'm not currently using IM so I'd prefer sticking to email and usenet...
Have a you been able to find any documentation on this stuff?
My main help was Benny/29A's article
"MSIL-PE-EXE infection strategies" on
http://vx.netlux.org/lib/vbe00.html and the source code to
"I-Worm.Serotonin" (in assembler :/ )
 
Hi, thanks for your immediate responce, I wonder... how did you get to copy
the IL Code???, the IMetaDataEmit interface deals only with the metadata, as
I understand I have to manually find the ".text" segment of the PE, this
segment include the IL code, then I use the RVA retrieved from the method
properties to extract the IL code BUT the new generated EXE doesn't work, I
guess I am doing something wrong here.... how did you get to copy the IL
Code??? any samples would be appriciated...

I'm at work atm so I don't have access to my code but i will post a code
sample tonight.

Until then:
Basically what I do is is call EnumMethods for all types, call
GetMethodProps, this gets me the codeRva which can be translated to get
a pointer to the IL code of the memory mapped file (method RvaToVa32 or
similar in imagehlp.lib), then I get the size of the IL code plus any
MORE_SECTS (containing the exception handling and other stuff).

Then I copy all of this into a buffer (all IL code for all methods,
you'll have to do some DWORD-aligning as well) and call
ICeeGen->GetILSection, then GetSectionBlock to allocate a buffer in the
ilsection, memcpy my IL buffer in there.
I also call SetRVA for every method because the RVA can change.

Well, it should become clearer when I post some sample code tonight.

i tested the assembly with peverify and this reports no errors (i found
the error wrt excption code in my last post).

I haven't tested it with embedded resources yet, this probably needs
more work...

have a look at http://vx.netlux.org/lib/vbe00.html
 
Hi Ben, Thanks for your responce, I wonder..., Did you used GetSectionBlock
to get a single block for the IL of all of the methods or you call
GetSectionBlock for each new method? do you call GetSectionRVA for each
method or do you call it once and calculate the RVA incrementally?
I am using 'COR_ILMETHOD::Emit' to emit the method header/signature and
memcpy to copy the IL Code, Still, I am doing something wrong... using ildasm
I can see that each of the 'copied' methods has a codesize of 0...
The following is a simpified snap of the code i use:
while(SUCCEEDED(hr = m_spMetaDataImport->EnumMethods(&enr
, tkClass
, &tok
, 1
, &count)) && count > 0)
{
hr = m_spMetaDataImport->GetMethodProps(tok
, &tkClass
, wszType
, sizeof(wszType)/sizeof(*wszType)
, 0
, &dwMethodAttr
, &pMethodSignature
, 0
, &dwCodeRVA
, &dwImplFlags);
Loader.getVAforRVA(dwCodeRVA, (void**)&pILHeader)
COR_ILMETHOD_DECODER method(pILHeader);


unsigned headerSize = COR_ILMETHOD::Size(&pILHeader->Fat, TRUE);

unsigned codeSizeAligned = pILHeader->Fat.GetCodeSize();


unsigned totalSize = headerSize + codeSizeAligned;

unsigned align = 4;
if (headerSize == 1)// Tiny headers don't need any alignement

align = 1;

hr = pContext->FileGen->GetSectionBlock(
pContext->IlSection
, totalSize
, align
, (void**)&raw_il_section);
raw_il_section += COR_ILMETHOD::Emit(headerSize
, &pILHeader->Fat
, TRUE
, raw_il_section);
memset(raw_il_section, 0, codeSizeAligned);

memcpy(raw_il_section, pILHeader->Fat.GetCode(), codeSizeAligned);

raw_il_section += codeSizeAligned;


hr = m_spMetaDataEmit->SetRVA(tok, pContext->IlSectionRVA);
pContext->IlSectionRVA += totalSize;
hr = pContext->FileGen->LinkCeeFile(pContext->ceeFile);
}
 
Hello Nadav

This is what I do:

[error checking etc removed]
_pCeeFileGen->CreateCeeFile(&_hCeeFile);
_pCeeFileGen->SetOutputFileName(_hCeeFile, fileName);

//call link so we can use GetSectionRVA
_pCeeFileGen->LinkCeeFile(_hCeeFile);

//get il section
HCEESECTION hSection;
_pCeeFileGen->GetIlSection (_hCeeFile, &hSection);

ULONG rva;
_pCeeFileGen->GetSectionRVA (hSection, &rva);

ULONG codeSize =0;
char* pBytes = NULL;

//get a new block just to get a pointer to the section, get 4 bytes for
DWORD alignement

_pCeeFileGen->GetSectionBlock (hSection, 4, 1,
reinterpret_cast<void**>(&pBytes));

unsigned int offset;
_pCeeFileGen->ComputeSectionOffset(hSection, pBytes, &offset);

//this copies all IL code into a buffer (_pILBuffer), see below
//also calls SetRVA for each method
GetILCode(&codeSize, rva + offset);

//get a new block large enough to hold IL Code (codezize - 4 bytes
//allocatd above)

char* pBytes2 = NULL;
_pCeeFileGen->GetSectionBlock (hSection, codeSize - 4, 1,
reinterpret_cast<void**>(&pBytes2));

//copy IL Code to section
memcpy(pBytes, _pILBuffer, codeSize);

_pCeeFileGen->EmitMetaDataEx(_hCeeFile, _pMetaDataEmit);
_pCeeFileGen->LinkCeeFile(_hCeeFile);
_pCeeFileGen->GenerateCeeFile(_hCeeFile);
_pCeeFileGen->DestroyCeeFile(&_hCeeFile);
delete[] _pILBuffer;



//==== GetILCode
HRESULT CAssemblyWriter::GetILCode(ULONG* pCodeSize, unsigned int offset) {
HRESULT hr = NULL;
//HACK: Allocate enough memory to hold entire .text section
int bufferSize = _pReader->GetPEFile()->_sizeOfTextSection;
_pILBuffer = new BYTE[bufferSize];
ZeroMemory(_pILBuffer, bufferSize);

int codeSize = 0;
//get all method of all types and add ILCode to buffer
std::vector<CTypeDef*> typeDefs = _pReader->_typeDefs;
for (unsigned int ii=0; ii < _pReader->_typeDefs.size(); ii++) {
CTypeDef* pType = _pReader->_typeDefs[ii];
for (unsigned jj = 0; jj < pType->_methodDefs.size(); jj++) {
CMethodDef* pMethod = pType->_methodDefs[jj];
if (pMethod->_codeSize > 0) {
int methodSize = pMethod->_codeSize + pMethod->_codeHeaderSize;
memcpy(_pILBuffer + codeSize, pMethod->_pCodeHeader, methodSize);

hr = _pMetaDataEmit->SetRVA(pMethod->_token, offset + codeSize);
if (!SUCCEEDED(hr)) {
return hr;
}
//HACK
if (pMethod->_name == L"Main") {
hr = _pCeeFileGen->SetEntryPoint(_hCeeFile, pMethod->_token);
if (!SUCCEEDED(hr)) {
return hr;
}
}
codeSize += methodSize;
codeSize = _ALIGN4(codeSize);
if (pMethod->_pStartExtraSections) {
memcpy(_pILBuffer + codeSize, pMethod->_pStartExtraSections,
pMethod->_sizeExtraSections);
codeSize += pMethod->_sizeExtraSections;
codeSize = _ALIGN4(codeSize);
}
}
}
}
*pCodeSize = codeSize;
return hr;
}


as you can see, I have all TypeDefs and methods in std::vectors

pMethod->_codeSize is the size of the IL Code and pMethod->_pCodeHeader
points to the start of the ILCode Header (CorILMethod_SmallFormat etc)

pMethod->_pStartExtraSections points to the extrasections like exception
handling if present
(http://msdn.microsoft.com/msdnmag/issues/03/09/NETProfilingAPI/default.aspx)

to translate the rva obtained from GetMethodProps I call

ImageRvaToVa(pNTHeaders, pBase, rva, NULL);

hth
 
Thanks fore your responce it was very helpful, I have managed to get the
Assembly copied, I have also managed to copy Exceptions functionality ( e.g.
COR_ILMETHOD_SECT_EH ) and to extract and update the entrypoint information,
I can send you a working sample...

I'm glad it helped a bit...
A sample would be nice (my email address is valid) but really only if
it isn't too much trouble. I got most things working myself now, however
I haven't yet looked into copying unmanaged embedded resources and
native code in a mixed mode module...
 
Back
Top