SlideShare a Scribd company logo
1 of 52
Download to read offline
Stealing	
  From	
  Thieves:	
  Breaking	
  
IonCube	
  VM	
  to	
  RE	
  Exploit	
  Kits	
  	
  
Mohamed	
  Saher	
  (@halsten)	
  
About	
  @halsten	
  
Reverse	
  Engineering	
  
Automa5on	
  of	
  RE	
  tasks	
  
Virtualiza5on	
  
Regular	
  project-­‐euler	
  problem	
  solver	
  (ranked	
  
#1	
  locally)	
  
•  Old	
  crackmes	
  writer	
  and	
  solver	
  
• 
• 
• 
• 
Contents	
  
• 
• 
• 
• 
• 
• 
• 

What	
  is	
  ionCube?	
  
Why	
  Protect?	
  
How	
  does	
  it	
  work?	
  
VM	
  Architecture	
  
VM	
  Internals	
  
ionCube	
  Loader	
  (SAMPLE)	
  
Breaking	
  ionCube	
  	
  
– 
– 
– 
– 
– 

Extracting	
  RAW	
  DATA	
  
Validating	
  RAW	
  DATA	
  
Processing	
  RAW	
  DATA	
  
Interpreting	
  the	
  Header	
  
Interpreting	
  the	
  Extra	
  Header	
  

•  Conclusion	
  
•  Q	
  &	
  A	
  
Not	
  Covered	
  
•  Recovering	
  the	
  license	
  file	
  	
  
•  Cracking	
  the	
  license	
  decryp5on	
  algorithm	
  
–  DRM	
  law	
  

•  Decompila5on	
  of	
  VM	
  Handlers	
  and	
  restoring	
  
original	
  PHP	
  source	
  
–  Out	
  of	
  scope	
  
What	
  is	
  ionCube?	
  
•  Packer/Compressor	
  
What	
  is	
  ionCube?	
  
•  Packer/Compressor	
  
•  Protector/Virtualizer	
  
Why	
  Protect?	
  
•  Intellectual	
  property	
  
Why	
  Protect?	
  
•  Intellectual	
  property	
  
–  Algorithm	
  implementa5on	
  
Why	
  Protect?	
  
•  Intellectual	
  property	
  
–  Algorithm	
  implementa5on	
  
–  Serial	
  checking	
  rou5nes	
  
Why	
  Protect?	
  
•  Intellectual	
  property	
  
–  Algorithm	
  implementa5on	
  
–  Serial	
  checking	
  rou5nes	
  
–  Hard-­‐coded	
  configura5ons	
  
Why	
  Protect?	
  
•  Intellectual	
  property	
  
–  Algorithm	
  implementa5on	
  
–  Serial	
  checking	
  rou5nes	
  
–  Hard-­‐coded	
  configura5ons	
  
…	
  	
  
Why	
  Protect?	
  
•  Intellectual	
  property	
  
–  Algorithm	
  implementa5on	
  
–  Serial	
  checking	
  rou5nes	
  
–  Hard-­‐coded	
  configura5ons	
  
…	
  	
  

•  Public	
  distribu5on	
  without	
  modifica5on	
  to	
  the	
  
original	
  source	
  
PE	
  Packer	
  vs.	
  PHP	
  Encoder	
  
•  Tradi5onal	
  PE	
  Packers	
  compress/protect	
  the	
  
x86	
  code	
  and	
  uses	
  its	
  stub	
  to	
  decompress/
unprotect	
  it	
  back	
  in	
  during	
  execu5on	
  
•  PHP	
  Encoders	
  has	
  to	
  rely	
  on	
  the	
  ZEND	
  
technology	
  (php-­‐>zend_opcodes)	
  	
  
How	
  does	
  it	
  work?	
  (Compila5on)	
  
How	
  does	
  it	
  work?	
  (Run-­‐Time)	
  
VM	
  Architecture	
  
•  Stack	
  based	
  VM	
  (example:	
  .NET,	
  Java)	
  
•  Byte	
  Code	
  is	
  obfuscated	
  a_er	
  compila5on	
  
•  Uses	
  some	
  crypto	
  for	
  VM	
  header	
  and	
  
parameter	
  encryp5on	
  
•  Uses	
  Zend	
  Engine	
  
VM	
  Internals	
  
•  Crypto	
  used	
  within	
  the	
  encoder	
  and	
  the	
  VM	
  
–  Custom	
  Base64	
  
–  Adler32	
  
–  CRC32	
  
–  SHA-­‐1	
  
–  MD5	
  
–  BlowFish	
  (Counter	
  Mode	
  Encryp5on	
  [CTR])	
  
–  Modified	
  Mersenne	
  Twister	
  
Example	
  of	
  a	
  Protected	
  PHP	
  File	
  
<?php //00337
if(!extension_loaded('ionCube Loader')){$__oc=strtolower(substr(php_uname(),0,3));
$__ln='/ioncube/ioncube_loader_'.$__oc.'_'.substr(phpversion(),0,3).
(($__oc=='win')?'.dll':'.so');$__oid=$__id=realpath(ini_get('extension_dir'));
$__here=dirname(__FILE__);if((@$__id[1])==':'){$__id=str_replace('
','/',substr($__id,2));$__here=str_replace('','/',substr($__here,2));}
$__rd=str_repeat('/..',substr_count($__id,'/')).$__here.'/';
$__i=strlen($__rd);while($__i--){if($__rd[$__i]=='/'){$__lp=substr($__rd,0,$__i).
$__ln;if(file_exists($__oid.$__lp)){$__ln=$__lp;break;}}}@dl($__ln);}else{echo('The
file '.__FILE__." is corrupted.n");return 0;}if(function_exists('_il_exec')){return
_il_exec();}echo('This encoded file cannot be run. Please run the file ioncubeloader-helper.php for more information.');return 0;
?>
4+oV5E3tizCOGmZayKycyFdfdNEYKcDQ2UctWQgi5wUMAYDSmMVeoLZpTJYlsb2ZS87vmUDNyJXy
u6mBqXBOY8uBDM8S9FpfYpOU8H2UybP4eoySb3gsXR3LRDVhZQOE547VladmAtDtg672Z0axEinz
4Q0KK4ySJmQf/y74+9n0mQxv89e/3ORP/KEy9C7qQ57ANCp167ft8uwqnxmMG2B0FghtwVsgbjWW
TRM9HpX9RfSRUpbRfJyiWM77aOjzW9XB2eAJyxqd/T5a5+EXVl7auGnQ2ZiQhbeeajCwKRwWP0X9
N8VmcedG2VriSa6TMSY++2C4zLx5FcRziK7DMb2vYBQA0IhN8SOiVv4t5JIzumywsmq9bHtAZLdU
62oKLWPotyYaB7R/+nSDX4s7Vwifp0nXJe8NQ5zI36p4UMmoZnHHKC/+oFab7U7rI4uC707fwrhr
b95eZu1QsG+TWFhNjn3Ao9UClGrvoye+fIL7xrq=
How	
  does	
  it	
  work?	
  (Internally)	
  
•  There’s	
  only	
  1	
  way	
  to	
  find	
  out,	
  lets	
  see	
  what	
  
the	
  loader	
  is	
  doing	
  under	
  the	
  hood	
  
Breaking	
  ionCube	
  
Extrac5ng	
  the	
  RAW	
  DATA	
  
•  Decode	
  the	
  RAW	
  DATA	
  using	
  a	
  custom	
  Base64	
  
character	
  set	
  
("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd
efghijklmnopqrstuvwxyz+/”)	
  	
  
	
  and	
  not	
  
(“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop
qrstuvwxyz0123456789+/”)	
  
4+oV5E3tizCOGmZayKycyFdfdNEYKcDQ2UctWQgi5wUMAYDSmMVeoLZpTJYlsb2ZS87vmUDNyJXy
u6mBqXBOY8uBDM8S9FpfYpOU8H2UybP4eoySb3gsXR3LRDVhZQOE547VladmAtDtg672Z0axEinz
4Q0KK4ySJmQf/y74+9n0mQxv89e/3ORP/KEy9C7qQ57ANCp167ft8uwqnxmMG2B0FghtwVsgbjWW
TRM9HpX9RfSRUpbRfJyiWM77aOjzW9XB2eAJyxqd/T5a5+EXVl7auGnQ2ZiQhbeeajCwKRwWP0X9
N8VmcedG2VriSa6TMSY++2C4zLx5FcRziK7DMb2vYBQA0IhN8SOiVv4t5JIzumywsmq9bHtAZLdU
62oKLWPotyYaB7R/+nSDX4s7Vwifp0nXJe8NQ5zI36p4UMmoZnHHKC/+oFab7U7rI4uC707fwrhr
b95eZu1QsG+TWFhNjn3Ao9UClGrvoye+fIL7xrq=

	
  
Breaking	
  ionCube	
  
Extrac5ng	
  the	
  RAW	
  DATA	
  
•  Check	
  for	
  encoded	
  VM	
  restric5ons	
  and	
  rules	
  
•  Header	
  size	
  (<?php	
  //0)	
  -­‐>	
  10	
  bytes	
  +	
  4	
  bytes	
  
(size	
  of	
  loader)	
  
•  Determine	
  the	
  star5ng	
  offset	
  of	
  the	
  loader	
  
Breaking	
  ionCube	
  
Extrac5ng	
  the	
  RAW	
  DATA	
  
•  Get	
  PHP	
  version	
  (DWORD)	
  
–  Compare	
  with	
  HARD-­‐CODED	
  values	
  (BINARY	
  
MODE)	
  
•  0xDEADC0DE	
  
•  0x3FBC2883	
  
•  0x217582F	
  
•  0x149FEC13	
  
•  0x67A6BF45	
  
•  0x9EB67AC2	
  
Breaking	
  ionCube	
  
Extrac5ng	
  the	
  RAW	
  DATA	
  
•  Compare	
  against	
  other	
  HARDCODED	
  values	
  
(BASE64	
  MODE)	
  
–  0y4h	
  
–  BrWN	
  
–  4+oV	
  
–  HR+c	
  
–  mdgs	
  
	
  
Breaking	
  ionCube	
  
Valida5ng	
  the	
  RAW	
  DATA	
  
•  Read	
  a	
  DWORD	
  for	
  the	
  VM	
  version	
  (0x00)	
  XOR	
  
the	
  value	
  with	
  0x2853CEF2	
  and	
  compare	
  with	
  
HARDCODED	
  values	
  
–  dwVer	
  =	
  ReadDWORD()	
  ^	
  0x2853CEF2	
  	
  
• 
• 
• 
• 
• 
• 
• 

0x17EFE61	
  (v1)	
  
0x2A4496DD	
  (v2)	
  
0x3CCC22E1	
  (v3)	
  
0x4FF571B7	
  (v4)	
  
0xA0780FF1	
  (v5)	
  
0xB6E5B430	
  (v6)	
  
0xF6FE0E2C	
  (v7)	
  
Breaking	
  ionCube	
  
Process	
  the	
  RAW	
  DATA	
  
•  Calculate	
  	
  dwFileSizeKey	
  (DWORD)	
  
–  dwFileSizeKey	
  =	
  ((dwRawBinaryDataSize	
  +	
  12321)	
  
^	
  0x23958CDE)	
  

•  Read	
  Header	
  Informa5on	
  (struct)	
  
–  dwHeaderFileSizeKey	
  (DWORD	
  +0x00)	
  
–  dwHeaderSize	
  (DWORD	
  +0x04)	
  
–  dwHeaderKey	
  (DWORD	
  +0x08)	
  
Breaking	
  ionCube	
  
Process	
  the	
  RAW	
  DATA	
  
•  Calculate	
  Header	
  Size	
  using	
  the	
  following	
  formula	
  
–  dwCalculatedHeaderSize	
  =	
  (((dwHeaderSize	
  ^	
  
0x184FF593)	
  +	
  (-­‐0x0C21672E))	
  ^	
  dwHeaderKey)	
  
–  dwFillData1	
  (DWORD	
  +0x0C)	
  
–  dwFillData2	
  (DWORD	
  +0x10)	
  
–  dwFillData3	
  (DWORD	
  +0x14)	
  

•  dwFillData1/dwFillData2/dwFillData3	
  (encoded	
  
during	
  run5me	
  with	
  0xFF	
  “<“)	
  
•  Calculate	
  Header	
  File	
  Size	
  Key	
  
–  dwCalculatedHeaderFileSizeKey	
  =	
  
(dwHeaderFileSizeKey	
  ^	
  dwHeaderKey)	
  
Breaking	
  ionCube	
  
Process	
  the	
  RAW	
  DATA	
  
•  Validate	
  Key	
  
–  If	
  (dwFileSizeKey	
  !=	
  
dwCalculatedHeaderFileSizeKey)	
  
•  Difference	
  -­‐>	
  ABS(dwFileSizeKey	
  	
  -­‐	
  
dwCalculatedHeaderFileSizeKey)	
  
•  Recover	
  the	
  Key	
  
–  dwNewCalculatedHeaderFileSizeKey	
  =	
  
((dwCalculatedHeaderFileSizeKey	
  –	
  12321)	
  ^	
  0x23958CDE)	
  

•  Ini5alize	
  MT	
  PRNG	
  with	
  dwHeaderKey	
  
Breaking	
  ionCube	
  
Process	
  the	
  RAW	
  DATA	
  
•  Read	
  the	
  Header	
  Data	
  and	
  Checksum	
  values.	
  
•  Header	
  consists	
  of	
  mul5ple	
  chunks	
  (struct)	
  
–  Parse	
  Header	
  Chunks	
  
•  Loop	
  while	
  (dwCounter	
  <=	
  dwCalculateHeaderSize)	
  
–  dwChunkFlag	
  (BYTE)	
  
–  dwChunkSize	
  (BYTE)	
  

–  Read	
  the	
  MD5	
  checksum	
  of	
  the	
  Raw	
  Data	
  (0x10	
  
BYTES)	
  
Breaking	
  ionCube	
  
Process	
  the	
  RAW	
  DATA	
  
•  Validate	
  ADLER32	
  checksum	
  for	
  the	
  encoded	
  VM	
  
–  START:	
  EncodedVM	
  +	
  0x04	
  
–  END:	
  EncodedVM.EOS	
  
	
  

4+oV5E3tizCOGmZayKycyFdfdNEYKcDQ2UctWQgi5wUMAYDSmMVeoLZpTJYlsb2ZS87vmUDNyJXy
u6mBqXBOY8uBDM8S9FpfYpOU8H2UybP4eoySb3gsXR3LRDVhZQOE547VladmAtDtg672Z0axEinz
4Q0KK4ySJmQf/y74+9n0mQxv89e/3ORP/KEy9C7qQ57ANCp167ft8uwqnxmMG2B0FghtwVsgbjWW
TRM9HpX9RfSRUpbRfJyiWM77aOjzW9XB2eAJyxqd/T5a5+EXVl7auGnQ2ZiQhbeeajCwKRwWP0X9
N8VmcedG2VriSa6TMSY++2C4zLx5FcRziK7DMb2vYBQA0IhN8SOiVv4t5JIzumywsmq9bHtAZLdU
62oKLWPotyYaB7R/+nSDX4s7Vwifp0nXJe8NQ5zI36p4UMmoZnHHKC/+oFab7U7rI4uC707fwrhr
b95eZu1QsG+TWFhNjn3Ao9UClGrvoye+fIL7xrq=

	
  

•  Extract	
  CRC	
  from	
  Header	
  	
  

–  dwCRC	
  ==	
  dwCalculatedADLER32	
  
Breaking	
  ionCube	
  
Process	
  the	
  RAW	
  DATA	
  
•  Decrypt	
  Chunk	
  Key	
  using	
  the	
  following	
  algorithm	
  
foreach	
  (BYTE	
  dwB	
  in	
  dwMD5Checksum)	
  {	
  
	
  ROR(dwB,	
  3)	
  
}	
  

•  Decrypt	
  Header	
  with	
  the	
  following	
  algorithm	
  
while	
  (Header.POSITION	
  !=	
  EOS)	
  {	
  
	
  while	
  (dwMD5Checksum.POS	
  !=	
  EOS)	
  {	
  
	
  
	
  x	
  =	
  ReadDWORD()	
  
	
  
	
  y	
  =	
  dwMD5Checksum.ReadBYTE()	
  
	
  
	
  z	
  =	
  (x	
  ^	
  Rand_MT(0xFF)	
  ^	
  y)	
  
	
  }	
  
}	
  

•  At	
  this	
  point	
  we	
  have	
  extracted	
  ionCube	
  Header	
  in	
  Binary	
  format	
  
	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Read	
  dwVersionData	
  for	
  the	
  Header	
  version	
  (DWORD)	
  
•  Read	
  dwMinimumLoaderVersion	
  (DWORD)	
  
•  Read	
  dwObfusca5onFlags	
  
–  Decode	
  dwObfusca5onFlags	
  
•  VARIABLES	
  -­‐>	
  0x0004	
  
•  FUNCTIONS	
  -­‐>	
  0x0008	
  

•  Read	
  dwHeaderCustomLoaderEventMessagesCount	
  
(DWORD)	
  
•  Read	
  a	
  fixed	
  sized	
  string	
  for	
  szObfusca5onHashSeed	
  
with	
  fixed	
  size	
  of	
  
dwHeaderCustomLoaderEventMessagesCount	
  	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Try	
  to	
  extract	
  dwByteCodeKey	
  
–  Doesn’t	
  exist?	
  
•  Assume	
  a	
  HARD-­‐CODED	
  value	
  of	
  0x363432	
  

–  Exists?	
  
•  Read	
  it	
  normally	
  
–  If	
  (dwByteCodeKey	
  ==	
  0x92A764C5)	
  
»  SPECIAL	
  CASE:	
  LicenseFile(+EnforceLicense)	
  
•  License	
  File	
  exists?	
  
•  YES:	
  GOOD	
  
•  NO:	
  Could	
  be	
  calculated	
  and	
  recovered	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Read	
  dwIncludedXORKey	
  (HARD-­‐CODED	
  value:	
  
0xE9FC23B1)	
  
•  Read	
  dwNumberOfStructsToRead	
  which	
  will	
  specify	
  
how	
  many	
  structures	
  to	
  read	
  based	
  on	
  the	
  encoding	
  of	
  
the	
  original	
  file	
  
–  LicenseString	
  (restricted	
  by	
  the	
  value	
  of	
  dwSize)	
  
•  dwDummy	
  (DWORD)	
  
•  dwSize	
  (DWORD)	
  

–  Check	
  for	
  DisableCheckingofLicenseRestric5on	
  (pointed	
  by	
  
dwDummy3)	
  
•  dwDummy1	
  (DWORD)	
  
•  dwDummy2	
  (DWORD)	
  
•  dwDummy3	
  (DWORD)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Check	
  for	
  LicensePassphrase	
  (restricted	
  by	
  the	
  value	
  of	
  
dwSize)	
  
–  dwDummy	
  (DWORD)	
  
–  dwSize	
  (DWORD)	
  

•  Check	
  if	
  there	
  is	
  a	
  CustomErrorCallback	
  file	
  (restricted	
  
by	
  the	
  value	
  of	
  dwSize)	
  
–  dwDummy	
  (DWORD)	
  
–  dwSize	
  (DWORD)	
  

•  Check	
  if	
  there	
  is	
  a	
  CustomErrorCallbackHandler	
  
(restricted	
  by	
  the	
  value	
  of	
  dwSize)	
  
–  dwDummy	
  (DWORD)	
  
–  dwSize	
  (DWORD)	
  	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Check	
  for	
  EnableAutoPrependAppendFile	
  
(pointed	
  by	
  dwDummy3)	
  
–  dwDummy1	
  
–  dwDummy2	
  
–  dwDummy3	
  

•  	
  Skip	
  2	
  dummy	
  DWORD	
  and	
  a	
  calculated	
  
number	
  of	
  bytes	
  
–  dwCalculatesBytes	
  =	
  
ABS(dwNumberOfStructsToRead	
  –	
  5)	
  	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Decode	
  the	
  CustomErrorMessages	
  (the	
  following)	
  with	
  the	
  later	
  algorithm	
  
– 
– 
– 
– 
– 
– 
– 
– 
– 
– 
– 
– 
– 

Corrupt-­‐file	
  
Expire-­‐file	
  
No-­‐permissions	
  
Clock-­‐skew	
  
Untrusted-­‐extension	
  
License-­‐not-­‐found	
  
License-­‐corrupt	
  
License-­‐expired	
  
License-­‐property-­‐invalid	
  
License-­‐server-­‐invalid	
  
Unauth-­‐including-­‐file	
  
Unauth-­‐included-­‐file	
  
Unauth-­‐append-­‐prepend-­‐file	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Read	
  dwNumberOfCustomizedErrorMessages	
  
which	
  will	
  determine	
  how	
  many	
  structs	
  to	
  
read	
  later	
  
•  Loop	
  through	
  
dwNumberOfCustomizedErrorMessages	
  and	
  
read	
  the	
  struct	
  
–  dwCustomErrorMsgID	
  (BYTE)	
  
–  szCustomErrorMsg	
  
•  WARNING:	
  NULL-­‐TERMINATED	
  strings	
  (skip	
  ’0’)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Decode	
  IncludeFileRestric5ons	
  
–  Read	
  
dbNumberOfIncludeRestric5onsEntriesToRead	
  
(BYTE)	
  
–  Loop	
  through	
  
dbNumberOfIncludeRestric5onsEntriesToRead	
  	
  
and	
  read	
  2	
  sets	
  of	
  arrays	
  of	
  structs	
  
•  Read	
  dbDummy	
  (BYTE)	
  [NOT	
  IMPORTANT]	
  
•  Set	
  1	
  (IncludeKey)	
  
•  Set	
  2	
  (IncludeKeyHandler)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Both	
  Set	
  1	
  and	
  2	
  need	
  to	
  be	
  decoded	
  using	
  
the	
  following	
  algorithm	
  
–  Read	
  wSize	
  (WORD)	
  
–  Calculate	
  Z	
  =	
  (wSize	
  ^	
  dwIncludeXORKey)	
  &	
  
65535)	
  
–  Using	
  the	
  calculated	
  Z	
  we	
  can	
  extract	
  the	
  full	
  data	
  
and	
  fully	
  decode	
  it	
  using	
  the	
  following	
  algorithm	
  
Do	
  {	
  
	
  a	
  =	
  ReadDWORD()	
  
	
  b	
  =	
  (a	
  ^	
  dwIncludedKey)	
  
}	
  while	
  (!EOS)	
  	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Read	
  dbNumberOfServerRestrictedItems	
  (BYTE)	
  
•  Loop	
  through	
  dbNumberOfServerRestrictedItems	
  
and	
  read	
  a	
  struct	
  
–  Read	
  dbNumberOfRows	
  (BYTE)	
  
–  Read	
  dbNumberOfColumns	
  (BYTE)	
  
•  Loop	
  through	
  dbNumberOfColumns	
  	
  
–  Read	
  dbDataType	
  (BYTE)	
  
»  Decode	
  dbDataType	
  
•  0	
  -­‐>	
  IP	
  
•  1	
  -­‐>	
  MAC	
  
•  3	
  -­‐>	
  NOT	
  IMPORTANT	
  
•  4	
  -­‐>	
  DOMAIN	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  IP	
  

–  Read	
  dbNumberOfIPEntries	
  

•  Loop	
  through	
  dbNumberOfIPEntries	
  
–  Read	
  dbUseNetMask	
  
»  0	
  -­‐>	
  will	
  use	
  netmask	
  
»  1	
  -­‐>	
  will	
  not	
  use	
  netmask	
  
–  Read	
  IP	
  Address	
  in	
  reverse	
  order	
  
»  dbIP4	
  
»  dbIP3	
  
»  dbIP2	
  
»  dbIP1	
  
–  Read	
  netmask	
  in	
  reverse	
  order	
  
»  dbNetMask4	
  
»  dbNetMask3	
  
»  dbNetMask2	
  
»  dbNetMask1	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  MAC	
  
–  Read	
  dbNumberOfMACEntries	
  
•  Loop	
  through	
  dbNumberOfMACEntries	
  
–  Read	
  szMAC	
  (6	
  BYTES)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Domain	
  
–  Read	
  dbNumberOfDomainEntries	
  
•  Loop	
  through	
  dbNumberOfDomainEntries	
  
–  Read	
  szDomain	
  (NULL-­‐TERMINATED)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Header	
  
•  Compute	
  dwCalculatedAdler32	
  for	
  the	
  
encoded	
  VM	
  
–  Difference	
  between	
  extracted	
  and	
  calculated?	
  
(Un/modified)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Extra	
  Header	
  
•  Read	
  0x28	
  bytes	
  which	
  contains	
  the	
  Extra	
  
Header	
  
•  Read	
  wMinorVersion	
  (WORD)	
  
•  Read	
  wMajorVersion	
  (WORD)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Extra	
  Header	
  
•  Read	
  dwPHPFlags	
  

–  Decode	
  dwPHPFlags	
  
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 
• 

0x001	
  
0x002	
  
0x004	
  
0x008	
  
0x010	
  
0x020	
  (allow	
  run	
  with	
  untrusted	
  extensions)	
  
0x040	
  (php5	
  body)	
  
0x080	
  (vm	
  handlers	
  are	
  encrypted)	
  
0x100	
  
0x200	
  (obfuscate	
  func5on	
  names)	
  
0x400	
  (encrypt	
  strings)	
  
0x800	
  (obfuscate	
  strip	
  line	
  numbers)	
  
0x1000	
  (obfuscate	
  variable	
  names)	
  
0x2000	
  (encryp5on	
  flag)	
  
0x4000	
  
0x8000	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Extra	
  Header	
  
• 
• 
• 
• 

Read	
  dbEncoderGenera5onNumber	
  (BYTE)	
  
Read	
  dbEncoderMajorNumber	
  (BYTE)	
  
Read	
  dbEncoderMinorNumber	
  (BYTE)	
  
Read	
  dbEncoderEnhancementNumber	
  (BYTE)	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Extra	
  Header	
  
•  Read	
  dwMemberID	
  (DWORD)	
  [registra5on	
  
data]	
  
If	
  (license	
  exists	
  	
  and	
  license	
  restric5ons	
  are	
  
enforced)	
  {	
  	
  
	
  dwByteCodeKey	
  =	
  (0x363432	
  +	
  RAND(_5me())	
  
}	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Extra	
  Header	
  
• 

Morph	
  the	
  dwByteCodeKey	
  using	
  the	
  following	
  algorithm	
  

If	
  (dwServerRestric5onItems	
  exists)	
  {	
  
	
  dwByteCode_MT_XORKey	
  =	
  (0x92492493	
  /	
  0x1000)	
  *	
  (dwByteCode_MT_InitKey	
  /	
  0x1000)	
  
dwByteCode_MT_XORKey	
  =	
  ByteCode_MT_XORKey	
  +	
  ByteCode_MT_InitKey)	
  
dwByteCode_MT_XORKey	
  =	
  (int)(dwByteCode_MT_XORKey	
  /	
  4)	
  
	
  
If	
  (dwByteCode_MT_XORKey	
  <	
  0)	
  {	
  
	
  dwByteCode_MT_XORKey++	
  
}	
  
	
  
dwByteCode_MT_XORKey	
  =	
  (dwByteCode_MT_XORKey	
  	
  -­‐	
  (13	
  *	
  dwServerRestric5onItems))	
  
	
  
}	
  
Else	
  {	
  
	
  dwByteCode_MT_XORKey	
  =	
  dwByteCode_MT_InitKey	
  
}	
  
	
  

((((dwByteCode_MT_InitKey	
  *	
  0x92492493	
  >>	
  32)	
  +	
  dwByteCode_MT_InitKey)	
  >>	
  2)	
  –	
  
13	
  *	
  dwServerRestric5onItems	
  
	
  
Breaking	
  ionCube	
  
Interpre5ng	
  the	
  Extra	
  Header	
  
• 
• 
• 
• 
• 
• 
• 

Read	
  dwCopyOfIncludedXORKey	
  (DWORD)	
  
Read	
  dwUnknown1	
  (DWORD)	
  
Read	
  dwUnknown2	
  (DWORD)	
  
Read	
  wUnknown3	
  (WORD)	
  
Read	
  dbUnknown4	
  (BYTE)	
  
Read	
  dbUnknown5	
  (BYTE)	
  
Read	
  dwEvalTimeMinEncryp5on	
  

–  dwEvalTimeMin	
  =	
  dwEvalTimeMinEncryp5on	
  +	
  10233976199	
  

•  Read	
  dwEvalTimeMaxEncryp5on	
  

–  dwEvalTimeMax	
  =	
  dwEvalTimeMaxEncryp5on	
  +	
  83941958	
  

•  0x4AD70D0D	
  -­‐>	
  16.10.2009	
  
•  0x740A9780	
  -­‐>	
  11.09.2031	
  
•  CONST	
  dwSecondsPerDay	
  =	
  86400	
  (24h	
  *	
  60m	
  *	
  60s)	
  
Conclusion	
  
•  VM	
  uses	
  a	
  simplis5c	
  Stack	
  based	
  approach	
  
•  Encryp5on/Encoding	
  methods	
  are	
  weak	
  and	
  
easily	
  broken	
  
•  Relies	
  too	
  much	
  on	
  XOR	
  based	
  encryp5on	
  
•  LOTS	
  of	
  HARD-­‐CODED	
  constants	
  
•  Loader	
  is	
  easily	
  patched	
  (no	
  protec5on,	
  x86	
  code	
  
easily	
  read)	
  
•  Couple	
  of	
  bugs	
  in	
  the	
  Loader	
  through	
  hand-­‐
cra_ed	
  VM	
  (exploitable?)	
  
Q	
  &	
  A	
  
•  Mohamed	
  Saher	
  
•  @halsten	
  
•  msaher@nsslabs.com	
  

More Related Content

What's hot

Redis — The AK-47 of Post-relational Databases
Redis — The AK-47 of Post-relational DatabasesRedis — The AK-47 of Post-relational Databases
Redis — The AK-47 of Post-relational Databases
Karel Minarik
 
So you want to liberate your data?
So you want to liberate your data?So you want to liberate your data?
So you want to liberate your data?
Mogens Heller Grabe
 

What's hot (20)

Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?
 
Everything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askEverything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to ask
 
Summary of JDK10 and What will come into JDK11
Summary of JDK10 and What will come into JDK11Summary of JDK10 and What will come into JDK11
Summary of JDK10 and What will come into JDK11
 
Summary of JDK10 and What will come into JDK11
Summary of JDK10 and What will come into JDK11Summary of JDK10 and What will come into JDK11
Summary of JDK10 and What will come into JDK11
 
Nodejs - A quick tour (v5)
Nodejs - A quick tour (v5)Nodejs - A quick tour (v5)
Nodejs - A quick tour (v5)
 
Redis And python at pycon_2011
Redis And python at pycon_2011Redis And python at pycon_2011
Redis And python at pycon_2011
 
Extend Redis with Modules
Extend Redis with ModulesExtend Redis with Modules
Extend Redis with Modules
 
Find bottleneck and tuning in Java Application
Find bottleneck and tuning in Java ApplicationFind bottleneck and tuning in Java Application
Find bottleneck and tuning in Java Application
 
Redis — The AK-47 of Post-relational Databases
Redis — The AK-47 of Post-relational DatabasesRedis — The AK-47 of Post-relational Databases
Redis — The AK-47 of Post-relational Databases
 
Keeping OpenStack storage trendy with Ceph and containers
Keeping OpenStack storage trendy with Ceph and containersKeeping OpenStack storage trendy with Ceph and containers
Keeping OpenStack storage trendy with Ceph and containers
 
Redis memcached pdf
Redis memcached pdfRedis memcached pdf
Redis memcached pdf
 
Apache Directory and the OSGi Service Platform - Enrique Rodriguez, PMC Membe...
Apache Directory and the OSGi Service Platform - Enrique Rodriguez, PMC Membe...Apache Directory and the OSGi Service Platform - Enrique Rodriguez, PMC Membe...
Apache Directory and the OSGi Service Platform - Enrique Rodriguez, PMC Membe...
 
How to cook lettuce @Java casual
How to cook lettuce @Java casualHow to cook lettuce @Java casual
How to cook lettuce @Java casual
 
Nodejs - A quick tour (v4)
Nodejs - A quick tour (v4)Nodejs - A quick tour (v4)
Nodejs - A quick tour (v4)
 
Distributed Lock Manager
Distributed Lock ManagerDistributed Lock Manager
Distributed Lock Manager
 
How Prometheus Store the Data
How Prometheus Store the DataHow Prometheus Store the Data
How Prometheus Store the Data
 
JRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVMJRuby 9000 - Optimizing Above the JVM
JRuby 9000 - Optimizing Above the JVM
 
So you want to liberate your data?
So you want to liberate your data?So you want to liberate your data?
So you want to liberate your data?
 
Terracotta's OffHeap Explained
Terracotta's OffHeap ExplainedTerracotta's OffHeap Explained
Terracotta's OffHeap Explained
 
Compromising Linux Virtual Machines with Debugging Mechanisms
Compromising Linux Virtual Machines with Debugging MechanismsCompromising Linux Virtual Machines with Debugging Mechanisms
Compromising Linux Virtual Machines with Debugging Mechanisms
 

Similar to Bh ad-12-stealing-from-thieves-saher-slides

OGG Architecture Performance
OGG Architecture PerformanceOGG Architecture Performance
OGG Architecture Performance
Enkitec
 
Oracle GoldenGate Architecture Performance
Oracle GoldenGate Architecture PerformanceOracle GoldenGate Architecture Performance
Oracle GoldenGate Architecture Performance
Enkitec
 

Similar to Bh ad-12-stealing-from-thieves-saher-slides (20)

Stealing from Thieves: Breaking IonCUBE VM to RE Exploit Kits
Stealing from Thieves: Breaking IonCUBE VM to RE Exploit KitsStealing from Thieves: Breaking IonCUBE VM to RE Exploit Kits
Stealing from Thieves: Breaking IonCUBE VM to RE Exploit Kits
 
SMP implementation for OpenBSD/sgi
SMP implementation for OpenBSD/sgiSMP implementation for OpenBSD/sgi
SMP implementation for OpenBSD/sgi
 
OGG Architecture Performance
OGG Architecture PerformanceOGG Architecture Performance
OGG Architecture Performance
 
Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)
Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)
Oracle GoldenGate Presentation from OTN Virtual Technology Summit - 7/9/14 (PDF)
 
Oracle GoldenGate Architecture Performance
Oracle GoldenGate Architecture PerformanceOracle GoldenGate Architecture Performance
Oracle GoldenGate Architecture Performance
 
Raffaele Rialdi
Raffaele RialdiRaffaele Rialdi
Raffaele Rialdi
 
Java Jit. Compilation and optimization by Andrey Kovalenko
Java Jit. Compilation and optimization by Andrey KovalenkoJava Jit. Compilation and optimization by Andrey Kovalenko
Java Jit. Compilation and optimization by Andrey Kovalenko
 
cinema_time_new.pdf
cinema_time_new.pdfcinema_time_new.pdf
cinema_time_new.pdf
 
Ice Age melting down: Intel features considered usefull!
Ice Age melting down: Intel features considered usefull!Ice Age melting down: Intel features considered usefull!
Ice Age melting down: Intel features considered usefull!
 
Eusecwest
EusecwestEusecwest
Eusecwest
 
DEF CON 27 - JESSE MICHAEL - get off the kernel if you can't drive
DEF CON 27 - JESSE MICHAEL - get off the kernel if you can't driveDEF CON 27 - JESSE MICHAEL - get off the kernel if you can't drive
DEF CON 27 - JESSE MICHAEL - get off the kernel if you can't drive
 
Project Basecamp: News From Camp 4
Project Basecamp: News From Camp 4Project Basecamp: News From Camp 4
Project Basecamp: News From Camp 4
 
Nikita Abdullin - Reverse-engineering of embedded MIPS devices. Case Study - ...
Nikita Abdullin - Reverse-engineering of embedded MIPS devices. Case Study - ...Nikita Abdullin - Reverse-engineering of embedded MIPS devices. Case Study - ...
Nikita Abdullin - Reverse-engineering of embedded MIPS devices. Case Study - ...
 
Can puppet help you run docker on a T2.Micro?
Can puppet help you run docker on a T2.Micro?Can puppet help you run docker on a T2.Micro?
Can puppet help you run docker on a T2.Micro?
 
Sista: Improving Cog’s JIT performance
Sista: Improving Cog’s JIT performanceSista: Improving Cog’s JIT performance
Sista: Improving Cog’s JIT performance
 
Linux kernel debugging
Linux kernel debuggingLinux kernel debugging
Linux kernel debugging
 
Power of linked list
Power of linked listPower of linked list
Power of linked list
 
NSC #2 - D3 02 - Peter Hlavaty - Attack on the Core
NSC #2 - D3 02 - Peter Hlavaty - Attack on the CoreNSC #2 - D3 02 - Peter Hlavaty - Attack on the Core
NSC #2 - D3 02 - Peter Hlavaty - Attack on the Core
 
Jvm memory model
Jvm memory modelJvm memory model
Jvm memory model
 
Where Django Caching Bust at the Seams
Where Django Caching Bust at the SeamsWhere Django Caching Bust at the Seams
Where Django Caching Bust at the Seams
 

Recently uploaded

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Modernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaModernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using Ballerina
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Decarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceDecarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational Performance
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern Enterprise
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by Anitaraj
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
API Governance and Monetization - The evolution of API governance
API Governance and Monetization -  The evolution of API governanceAPI Governance and Monetization -  The evolution of API governance
API Governance and Monetization - The evolution of API governance
 
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software Engineering
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Less Is More: Utilizing Ballerina to Architect a Cloud Data Platform
Less Is More: Utilizing Ballerina to Architect a Cloud Data PlatformLess Is More: Utilizing Ballerina to Architect a Cloud Data Platform
Less Is More: Utilizing Ballerina to Architect a Cloud Data Platform
 
Quantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation ComputingQuantum Leap in Next-Generation Computing
Quantum Leap in Next-Generation Computing
 

Bh ad-12-stealing-from-thieves-saher-slides

  • 1. Stealing  From  Thieves:  Breaking   IonCube  VM  to  RE  Exploit  Kits     Mohamed  Saher  (@halsten)  
  • 2. About  @halsten   Reverse  Engineering   Automa5on  of  RE  tasks   Virtualiza5on   Regular  project-­‐euler  problem  solver  (ranked   #1  locally)   •  Old  crackmes  writer  and  solver   •  •  •  • 
  • 3. Contents   •  •  •  •  •  •  •  What  is  ionCube?   Why  Protect?   How  does  it  work?   VM  Architecture   VM  Internals   ionCube  Loader  (SAMPLE)   Breaking  ionCube     –  –  –  –  –  Extracting  RAW  DATA   Validating  RAW  DATA   Processing  RAW  DATA   Interpreting  the  Header   Interpreting  the  Extra  Header   •  Conclusion   •  Q  &  A  
  • 4. Not  Covered   •  Recovering  the  license  file     •  Cracking  the  license  decryp5on  algorithm   –  DRM  law   •  Decompila5on  of  VM  Handlers  and  restoring   original  PHP  source   –  Out  of  scope  
  • 5. What  is  ionCube?   •  Packer/Compressor  
  • 6. What  is  ionCube?   •  Packer/Compressor   •  Protector/Virtualizer  
  • 7. Why  Protect?   •  Intellectual  property  
  • 8. Why  Protect?   •  Intellectual  property   –  Algorithm  implementa5on  
  • 9. Why  Protect?   •  Intellectual  property   –  Algorithm  implementa5on   –  Serial  checking  rou5nes  
  • 10. Why  Protect?   •  Intellectual  property   –  Algorithm  implementa5on   –  Serial  checking  rou5nes   –  Hard-­‐coded  configura5ons  
  • 11. Why  Protect?   •  Intellectual  property   –  Algorithm  implementa5on   –  Serial  checking  rou5nes   –  Hard-­‐coded  configura5ons   …    
  • 12. Why  Protect?   •  Intellectual  property   –  Algorithm  implementa5on   –  Serial  checking  rou5nes   –  Hard-­‐coded  configura5ons   …     •  Public  distribu5on  without  modifica5on  to  the   original  source  
  • 13. PE  Packer  vs.  PHP  Encoder   •  Tradi5onal  PE  Packers  compress/protect  the   x86  code  and  uses  its  stub  to  decompress/ unprotect  it  back  in  during  execu5on   •  PHP  Encoders  has  to  rely  on  the  ZEND   technology  (php-­‐>zend_opcodes)    
  • 14. How  does  it  work?  (Compila5on)  
  • 15. How  does  it  work?  (Run-­‐Time)  
  • 16. VM  Architecture   •  Stack  based  VM  (example:  .NET,  Java)   •  Byte  Code  is  obfuscated  a_er  compila5on   •  Uses  some  crypto  for  VM  header  and   parameter  encryp5on   •  Uses  Zend  Engine  
  • 17. VM  Internals   •  Crypto  used  within  the  encoder  and  the  VM   –  Custom  Base64   –  Adler32   –  CRC32   –  SHA-­‐1   –  MD5   –  BlowFish  (Counter  Mode  Encryp5on  [CTR])   –  Modified  Mersenne  Twister  
  • 18. Example  of  a  Protected  PHP  File   <?php //00337 if(!extension_loaded('ionCube Loader')){$__oc=strtolower(substr(php_uname(),0,3)); $__ln='/ioncube/ioncube_loader_'.$__oc.'_'.substr(phpversion(),0,3). (($__oc=='win')?'.dll':'.so');$__oid=$__id=realpath(ini_get('extension_dir')); $__here=dirname(__FILE__);if((@$__id[1])==':'){$__id=str_replace(' ','/',substr($__id,2));$__here=str_replace('','/',substr($__here,2));} $__rd=str_repeat('/..',substr_count($__id,'/')).$__here.'/'; $__i=strlen($__rd);while($__i--){if($__rd[$__i]=='/'){$__lp=substr($__rd,0,$__i). $__ln;if(file_exists($__oid.$__lp)){$__ln=$__lp;break;}}}@dl($__ln);}else{echo('The file '.__FILE__." is corrupted.n");return 0;}if(function_exists('_il_exec')){return _il_exec();}echo('This encoded file cannot be run. Please run the file ioncubeloader-helper.php for more information.');return 0; ?> 4+oV5E3tizCOGmZayKycyFdfdNEYKcDQ2UctWQgi5wUMAYDSmMVeoLZpTJYlsb2ZS87vmUDNyJXy u6mBqXBOY8uBDM8S9FpfYpOU8H2UybP4eoySb3gsXR3LRDVhZQOE547VladmAtDtg672Z0axEinz 4Q0KK4ySJmQf/y74+9n0mQxv89e/3ORP/KEy9C7qQ57ANCp167ft8uwqnxmMG2B0FghtwVsgbjWW TRM9HpX9RfSRUpbRfJyiWM77aOjzW9XB2eAJyxqd/T5a5+EXVl7auGnQ2ZiQhbeeajCwKRwWP0X9 N8VmcedG2VriSa6TMSY++2C4zLx5FcRziK7DMb2vYBQA0IhN8SOiVv4t5JIzumywsmq9bHtAZLdU 62oKLWPotyYaB7R/+nSDX4s7Vwifp0nXJe8NQ5zI36p4UMmoZnHHKC/+oFab7U7rI4uC707fwrhr b95eZu1QsG+TWFhNjn3Ao9UClGrvoye+fIL7xrq=
  • 19. How  does  it  work?  (Internally)   •  There’s  only  1  way  to  find  out,  lets  see  what   the  loader  is  doing  under  the  hood  
  • 20. Breaking  ionCube   Extrac5ng  the  RAW  DATA   •  Decode  the  RAW  DATA  using  a  custom  Base64   character  set   ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd efghijklmnopqrstuvwxyz+/”)      and  not   (“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop qrstuvwxyz0123456789+/”)   4+oV5E3tizCOGmZayKycyFdfdNEYKcDQ2UctWQgi5wUMAYDSmMVeoLZpTJYlsb2ZS87vmUDNyJXy u6mBqXBOY8uBDM8S9FpfYpOU8H2UybP4eoySb3gsXR3LRDVhZQOE547VladmAtDtg672Z0axEinz 4Q0KK4ySJmQf/y74+9n0mQxv89e/3ORP/KEy9C7qQ57ANCp167ft8uwqnxmMG2B0FghtwVsgbjWW TRM9HpX9RfSRUpbRfJyiWM77aOjzW9XB2eAJyxqd/T5a5+EXVl7auGnQ2ZiQhbeeajCwKRwWP0X9 N8VmcedG2VriSa6TMSY++2C4zLx5FcRziK7DMb2vYBQA0IhN8SOiVv4t5JIzumywsmq9bHtAZLdU 62oKLWPotyYaB7R/+nSDX4s7Vwifp0nXJe8NQ5zI36p4UMmoZnHHKC/+oFab7U7rI4uC707fwrhr b95eZu1QsG+TWFhNjn3Ao9UClGrvoye+fIL7xrq=  
  • 21. Breaking  ionCube   Extrac5ng  the  RAW  DATA   •  Check  for  encoded  VM  restric5ons  and  rules   •  Header  size  (<?php  //0)  -­‐>  10  bytes  +  4  bytes   (size  of  loader)   •  Determine  the  star5ng  offset  of  the  loader  
  • 22. Breaking  ionCube   Extrac5ng  the  RAW  DATA   •  Get  PHP  version  (DWORD)   –  Compare  with  HARD-­‐CODED  values  (BINARY   MODE)   •  0xDEADC0DE   •  0x3FBC2883   •  0x217582F   •  0x149FEC13   •  0x67A6BF45   •  0x9EB67AC2  
  • 23. Breaking  ionCube   Extrac5ng  the  RAW  DATA   •  Compare  against  other  HARDCODED  values   (BASE64  MODE)   –  0y4h   –  BrWN   –  4+oV   –  HR+c   –  mdgs    
  • 24. Breaking  ionCube   Valida5ng  the  RAW  DATA   •  Read  a  DWORD  for  the  VM  version  (0x00)  XOR   the  value  with  0x2853CEF2  and  compare  with   HARDCODED  values   –  dwVer  =  ReadDWORD()  ^  0x2853CEF2     •  •  •  •  •  •  •  0x17EFE61  (v1)   0x2A4496DD  (v2)   0x3CCC22E1  (v3)   0x4FF571B7  (v4)   0xA0780FF1  (v5)   0xB6E5B430  (v6)   0xF6FE0E2C  (v7)  
  • 25. Breaking  ionCube   Process  the  RAW  DATA   •  Calculate    dwFileSizeKey  (DWORD)   –  dwFileSizeKey  =  ((dwRawBinaryDataSize  +  12321)   ^  0x23958CDE)   •  Read  Header  Informa5on  (struct)   –  dwHeaderFileSizeKey  (DWORD  +0x00)   –  dwHeaderSize  (DWORD  +0x04)   –  dwHeaderKey  (DWORD  +0x08)  
  • 26. Breaking  ionCube   Process  the  RAW  DATA   •  Calculate  Header  Size  using  the  following  formula   –  dwCalculatedHeaderSize  =  (((dwHeaderSize  ^   0x184FF593)  +  (-­‐0x0C21672E))  ^  dwHeaderKey)   –  dwFillData1  (DWORD  +0x0C)   –  dwFillData2  (DWORD  +0x10)   –  dwFillData3  (DWORD  +0x14)   •  dwFillData1/dwFillData2/dwFillData3  (encoded   during  run5me  with  0xFF  “<“)   •  Calculate  Header  File  Size  Key   –  dwCalculatedHeaderFileSizeKey  =   (dwHeaderFileSizeKey  ^  dwHeaderKey)  
  • 27. Breaking  ionCube   Process  the  RAW  DATA   •  Validate  Key   –  If  (dwFileSizeKey  !=   dwCalculatedHeaderFileSizeKey)   •  Difference  -­‐>  ABS(dwFileSizeKey    -­‐   dwCalculatedHeaderFileSizeKey)   •  Recover  the  Key   –  dwNewCalculatedHeaderFileSizeKey  =   ((dwCalculatedHeaderFileSizeKey  –  12321)  ^  0x23958CDE)   •  Ini5alize  MT  PRNG  with  dwHeaderKey  
  • 28. Breaking  ionCube   Process  the  RAW  DATA   •  Read  the  Header  Data  and  Checksum  values.   •  Header  consists  of  mul5ple  chunks  (struct)   –  Parse  Header  Chunks   •  Loop  while  (dwCounter  <=  dwCalculateHeaderSize)   –  dwChunkFlag  (BYTE)   –  dwChunkSize  (BYTE)   –  Read  the  MD5  checksum  of  the  Raw  Data  (0x10   BYTES)  
  • 29. Breaking  ionCube   Process  the  RAW  DATA   •  Validate  ADLER32  checksum  for  the  encoded  VM   –  START:  EncodedVM  +  0x04   –  END:  EncodedVM.EOS     4+oV5E3tizCOGmZayKycyFdfdNEYKcDQ2UctWQgi5wUMAYDSmMVeoLZpTJYlsb2ZS87vmUDNyJXy u6mBqXBOY8uBDM8S9FpfYpOU8H2UybP4eoySb3gsXR3LRDVhZQOE547VladmAtDtg672Z0axEinz 4Q0KK4ySJmQf/y74+9n0mQxv89e/3ORP/KEy9C7qQ57ANCp167ft8uwqnxmMG2B0FghtwVsgbjWW TRM9HpX9RfSRUpbRfJyiWM77aOjzW9XB2eAJyxqd/T5a5+EXVl7auGnQ2ZiQhbeeajCwKRwWP0X9 N8VmcedG2VriSa6TMSY++2C4zLx5FcRziK7DMb2vYBQA0IhN8SOiVv4t5JIzumywsmq9bHtAZLdU 62oKLWPotyYaB7R/+nSDX4s7Vwifp0nXJe8NQ5zI36p4UMmoZnHHKC/+oFab7U7rI4uC707fwrhr b95eZu1QsG+TWFhNjn3Ao9UClGrvoye+fIL7xrq=   •  Extract  CRC  from  Header     –  dwCRC  ==  dwCalculatedADLER32  
  • 30. Breaking  ionCube   Process  the  RAW  DATA   •  Decrypt  Chunk  Key  using  the  following  algorithm   foreach  (BYTE  dwB  in  dwMD5Checksum)  {    ROR(dwB,  3)   }   •  Decrypt  Header  with  the  following  algorithm   while  (Header.POSITION  !=  EOS)  {    while  (dwMD5Checksum.POS  !=  EOS)  {      x  =  ReadDWORD()      y  =  dwMD5Checksum.ReadBYTE()      z  =  (x  ^  Rand_MT(0xFF)  ^  y)    }   }   •  At  this  point  we  have  extracted  ionCube  Header  in  Binary  format    
  • 31. Breaking  ionCube   Interpre5ng  the  Header   •  Read  dwVersionData  for  the  Header  version  (DWORD)   •  Read  dwMinimumLoaderVersion  (DWORD)   •  Read  dwObfusca5onFlags   –  Decode  dwObfusca5onFlags   •  VARIABLES  -­‐>  0x0004   •  FUNCTIONS  -­‐>  0x0008   •  Read  dwHeaderCustomLoaderEventMessagesCount   (DWORD)   •  Read  a  fixed  sized  string  for  szObfusca5onHashSeed   with  fixed  size  of   dwHeaderCustomLoaderEventMessagesCount    
  • 32. Breaking  ionCube   Interpre5ng  the  Header   •  Try  to  extract  dwByteCodeKey   –  Doesn’t  exist?   •  Assume  a  HARD-­‐CODED  value  of  0x363432   –  Exists?   •  Read  it  normally   –  If  (dwByteCodeKey  ==  0x92A764C5)   »  SPECIAL  CASE:  LicenseFile(+EnforceLicense)   •  License  File  exists?   •  YES:  GOOD   •  NO:  Could  be  calculated  and  recovered  
  • 33. Breaking  ionCube   Interpre5ng  the  Header   •  Read  dwIncludedXORKey  (HARD-­‐CODED  value:   0xE9FC23B1)   •  Read  dwNumberOfStructsToRead  which  will  specify   how  many  structures  to  read  based  on  the  encoding  of   the  original  file   –  LicenseString  (restricted  by  the  value  of  dwSize)   •  dwDummy  (DWORD)   •  dwSize  (DWORD)   –  Check  for  DisableCheckingofLicenseRestric5on  (pointed  by   dwDummy3)   •  dwDummy1  (DWORD)   •  dwDummy2  (DWORD)   •  dwDummy3  (DWORD)  
  • 34. Breaking  ionCube   Interpre5ng  the  Header   •  Check  for  LicensePassphrase  (restricted  by  the  value  of   dwSize)   –  dwDummy  (DWORD)   –  dwSize  (DWORD)   •  Check  if  there  is  a  CustomErrorCallback  file  (restricted   by  the  value  of  dwSize)   –  dwDummy  (DWORD)   –  dwSize  (DWORD)   •  Check  if  there  is  a  CustomErrorCallbackHandler   (restricted  by  the  value  of  dwSize)   –  dwDummy  (DWORD)   –  dwSize  (DWORD)    
  • 35. Breaking  ionCube   Interpre5ng  the  Header   •  Check  for  EnableAutoPrependAppendFile   (pointed  by  dwDummy3)   –  dwDummy1   –  dwDummy2   –  dwDummy3   •   Skip  2  dummy  DWORD  and  a  calculated   number  of  bytes   –  dwCalculatesBytes  =   ABS(dwNumberOfStructsToRead  –  5)    
  • 36. Breaking  ionCube   Interpre5ng  the  Header   •  Decode  the  CustomErrorMessages  (the  following)  with  the  later  algorithm   –  –  –  –  –  –  –  –  –  –  –  –  –  Corrupt-­‐file   Expire-­‐file   No-­‐permissions   Clock-­‐skew   Untrusted-­‐extension   License-­‐not-­‐found   License-­‐corrupt   License-­‐expired   License-­‐property-­‐invalid   License-­‐server-­‐invalid   Unauth-­‐including-­‐file   Unauth-­‐included-­‐file   Unauth-­‐append-­‐prepend-­‐file  
  • 37. Breaking  ionCube   Interpre5ng  the  Header   •  Read  dwNumberOfCustomizedErrorMessages   which  will  determine  how  many  structs  to   read  later   •  Loop  through   dwNumberOfCustomizedErrorMessages  and   read  the  struct   –  dwCustomErrorMsgID  (BYTE)   –  szCustomErrorMsg   •  WARNING:  NULL-­‐TERMINATED  strings  (skip  ’0’)  
  • 38. Breaking  ionCube   Interpre5ng  the  Header   •  Decode  IncludeFileRestric5ons   –  Read   dbNumberOfIncludeRestric5onsEntriesToRead   (BYTE)   –  Loop  through   dbNumberOfIncludeRestric5onsEntriesToRead     and  read  2  sets  of  arrays  of  structs   •  Read  dbDummy  (BYTE)  [NOT  IMPORTANT]   •  Set  1  (IncludeKey)   •  Set  2  (IncludeKeyHandler)  
  • 39. Breaking  ionCube   Interpre5ng  the  Header   •  Both  Set  1  and  2  need  to  be  decoded  using   the  following  algorithm   –  Read  wSize  (WORD)   –  Calculate  Z  =  (wSize  ^  dwIncludeXORKey)  &   65535)   –  Using  the  calculated  Z  we  can  extract  the  full  data   and  fully  decode  it  using  the  following  algorithm   Do  {    a  =  ReadDWORD()    b  =  (a  ^  dwIncludedKey)   }  while  (!EOS)    
  • 40. Breaking  ionCube   Interpre5ng  the  Header   •  Read  dbNumberOfServerRestrictedItems  (BYTE)   •  Loop  through  dbNumberOfServerRestrictedItems   and  read  a  struct   –  Read  dbNumberOfRows  (BYTE)   –  Read  dbNumberOfColumns  (BYTE)   •  Loop  through  dbNumberOfColumns     –  Read  dbDataType  (BYTE)   »  Decode  dbDataType   •  0  -­‐>  IP   •  1  -­‐>  MAC   •  3  -­‐>  NOT  IMPORTANT   •  4  -­‐>  DOMAIN  
  • 41. Breaking  ionCube   Interpre5ng  the  Header   •  IP   –  Read  dbNumberOfIPEntries   •  Loop  through  dbNumberOfIPEntries   –  Read  dbUseNetMask   »  0  -­‐>  will  use  netmask   »  1  -­‐>  will  not  use  netmask   –  Read  IP  Address  in  reverse  order   »  dbIP4   »  dbIP3   »  dbIP2   »  dbIP1   –  Read  netmask  in  reverse  order   »  dbNetMask4   »  dbNetMask3   »  dbNetMask2   »  dbNetMask1  
  • 42. Breaking  ionCube   Interpre5ng  the  Header   •  MAC   –  Read  dbNumberOfMACEntries   •  Loop  through  dbNumberOfMACEntries   –  Read  szMAC  (6  BYTES)  
  • 43. Breaking  ionCube   Interpre5ng  the  Header   •  Domain   –  Read  dbNumberOfDomainEntries   •  Loop  through  dbNumberOfDomainEntries   –  Read  szDomain  (NULL-­‐TERMINATED)  
  • 44. Breaking  ionCube   Interpre5ng  the  Header   •  Compute  dwCalculatedAdler32  for  the   encoded  VM   –  Difference  between  extracted  and  calculated?   (Un/modified)  
  • 45. Breaking  ionCube   Interpre5ng  the  Extra  Header   •  Read  0x28  bytes  which  contains  the  Extra   Header   •  Read  wMinorVersion  (WORD)   •  Read  wMajorVersion  (WORD)  
  • 46. Breaking  ionCube   Interpre5ng  the  Extra  Header   •  Read  dwPHPFlags   –  Decode  dwPHPFlags   •  •  •  •  •  •  •  •  •  •  •  •  •  •  •  •  0x001   0x002   0x004   0x008   0x010   0x020  (allow  run  with  untrusted  extensions)   0x040  (php5  body)   0x080  (vm  handlers  are  encrypted)   0x100   0x200  (obfuscate  func5on  names)   0x400  (encrypt  strings)   0x800  (obfuscate  strip  line  numbers)   0x1000  (obfuscate  variable  names)   0x2000  (encryp5on  flag)   0x4000   0x8000  
  • 47. Breaking  ionCube   Interpre5ng  the  Extra  Header   •  •  •  •  Read  dbEncoderGenera5onNumber  (BYTE)   Read  dbEncoderMajorNumber  (BYTE)   Read  dbEncoderMinorNumber  (BYTE)   Read  dbEncoderEnhancementNumber  (BYTE)  
  • 48. Breaking  ionCube   Interpre5ng  the  Extra  Header   •  Read  dwMemberID  (DWORD)  [registra5on   data]   If  (license  exists    and  license  restric5ons  are   enforced)  {      dwByteCodeKey  =  (0x363432  +  RAND(_5me())   }  
  • 49. Breaking  ionCube   Interpre5ng  the  Extra  Header   •  Morph  the  dwByteCodeKey  using  the  following  algorithm   If  (dwServerRestric5onItems  exists)  {    dwByteCode_MT_XORKey  =  (0x92492493  /  0x1000)  *  (dwByteCode_MT_InitKey  /  0x1000)   dwByteCode_MT_XORKey  =  ByteCode_MT_XORKey  +  ByteCode_MT_InitKey)   dwByteCode_MT_XORKey  =  (int)(dwByteCode_MT_XORKey  /  4)     If  (dwByteCode_MT_XORKey  <  0)  {    dwByteCode_MT_XORKey++   }     dwByteCode_MT_XORKey  =  (dwByteCode_MT_XORKey    -­‐  (13  *  dwServerRestric5onItems))     }   Else  {    dwByteCode_MT_XORKey  =  dwByteCode_MT_InitKey   }     ((((dwByteCode_MT_InitKey  *  0x92492493  >>  32)  +  dwByteCode_MT_InitKey)  >>  2)  –   13  *  dwServerRestric5onItems    
  • 50. Breaking  ionCube   Interpre5ng  the  Extra  Header   •  •  •  •  •  •  •  Read  dwCopyOfIncludedXORKey  (DWORD)   Read  dwUnknown1  (DWORD)   Read  dwUnknown2  (DWORD)   Read  wUnknown3  (WORD)   Read  dbUnknown4  (BYTE)   Read  dbUnknown5  (BYTE)   Read  dwEvalTimeMinEncryp5on   –  dwEvalTimeMin  =  dwEvalTimeMinEncryp5on  +  10233976199   •  Read  dwEvalTimeMaxEncryp5on   –  dwEvalTimeMax  =  dwEvalTimeMaxEncryp5on  +  83941958   •  0x4AD70D0D  -­‐>  16.10.2009   •  0x740A9780  -­‐>  11.09.2031   •  CONST  dwSecondsPerDay  =  86400  (24h  *  60m  *  60s)  
  • 51. Conclusion   •  VM  uses  a  simplis5c  Stack  based  approach   •  Encryp5on/Encoding  methods  are  weak  and   easily  broken   •  Relies  too  much  on  XOR  based  encryp5on   •  LOTS  of  HARD-­‐CODED  constants   •  Loader  is  easily  patched  (no  protec5on,  x86  code   easily  read)   •  Couple  of  bugs  in  the  Loader  through  hand-­‐ cra_ed  VM  (exploitable?)  
  • 52. Q  &  A   •  Mohamed  Saher   •  @halsten   •  msaher@nsslabs.com