Archive

Posts Tagged ‘php’

get Name and email address from a “from” email header

June 16th, 2010 Ivan Villareal No comments

This is a quick post of a little function I did to get the name and the email of a “from” header, Because this is not a standard thing this function only recognizes the following format:

Some Name <someemail @server.com></someemail>

this is the function I came up:

function extractEmailAddress($subject)
    {
        $result = new stdClass();
        if (preg_match('/\\b[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b/i', $subject, $regs)) {
            $result->email = $regs[0];
        }
        //try to get the name
        preg_match_all('/(.*)< (.*)>/', $subject, $regs, PREG_PATTERN_ORDER);
        if (isset($regs[1][0])) {
            $result->name = ($regs[1][0] != '') ? $regs[1][0] : '';
        } else {
            $result->name = '';
        }
        return $result;
    }

And this are some results I had:

Case 1:

$testName = "Ivan Villareal <ivan @server.com>";  </ivan>

Result:
object(stdClass)#3 (2) {
  ["email"]=>
  string(15) "ivan@server.com"
  ["name"]=>
  string(15) "Ivan Villareal "
}

Case 2:

$testName = "Ivan Villareal ivan@server.com"; 

Result:
object(stdClass)#3 (2) {
  ["email"]=>
  string(15) "ivan@server.com"
  ["name"]=>
  string(0) ""
}

Case 3:

$testName = "ivan@server.com";

Result:
object(stdClass)#3 (2) {
  ["email"]=>
  string(15) "ivan@server.com"
  ["name"]=>
  string(0) ""
}

Categories: Development, PHP Tags: , , , ,

Fetching mail from a POP3 server with Zend_Mail

June 9th, 2010 Ivan Villareal No comments

I was in a need for a class to get mails from a pop server to process them, so I’ve decided to leverage the Zend_Mail class, what I did was to create a wrapper around the Zend_Mail, to return all the messages from the server in a manageable way.

The first step was to put the needed Zend files in my library folder:

lib/Zend/Mail.php
Mail
|-- Exception.php
|-- Message
|   |-- File.php
|   `-- Interface.php
|-- Message.php
|-- Part
|   |-- File.php
|   `-- Interface.php
|-- Part.php
|-- Protocol
|   |-- Abstract.php
|   |-- Exception.php
|   |-- Imap.php
|   |-- Pop3.php
|   |-- Smtp
|   |   `-- Auth
|   |       |-- Crammd5.php
|   |       |-- Login.php
|   |       `-- Plain.php
|   `-- Smtp.php
|-- Storage
|   |-- Abstract.php
|   |-- Exception.php
|   |-- Folder
|   |   |-- Interface.php
|   |   |-- Maildir.php
|   |   `-- Mbox.php
|   |-- Folder.php
|   |-- Imap.php
|   |-- Maildir.php
|   |-- Mbox.php
|   |-- Pop3.php
|   `-- Writable
|       |-- Interface.php
|       `-- Maildir.php
|-- Storage.php
`-- Transport
    |-- Abstract.php
    |-- Exception.php
    |-- Sendmail.php
    `-- Smtp.php

Then I started writing my class:

< ?php
 
set_include_path('lib' . PATH_SEPARATOR . get_include_path());
 
include_once 'Zend/Mail.php';
include_once 'Zend/Mail/Storage/Pop3.php';
include_once 'Zend/Mail/Transport/Smtp.php';
include_once 'Zend/Mime/Part.php';
 
/**
 * Class to get mails from a server
 */
class mailFetcher
{
    private $_emailHost = 'pop.server.com';
    private $_emailUser = 'ivan@ivanvillareal.com';
    private $_emailPass = 'password';
	/**
	 * Zend_Mail_Storage
	 */
    private $_mail;
	/**
	 * Inbox wrapper
	 */
	private $_inbox = array();
 
	/**
	 * on class instantiation we fire connect
	 * to the pop server and start fetching the mails
	 */
    public function __construct()
    {
        try {
            $this->_mail = new Zend_Mail_Storage_Pop3(array(
                                             'host' => $this->_emailHost,
                                             'user' => $this->_emailUser,
                                             'password' => $this->_emailPass));
        } catch (Exception $e) {
            echo 'Mail Retrieval Failed...' . PHP_EOL;
            die();
        }      
        $this->processMail();
    }
 
 
	private function _contentDecoder($encoding, $content)
	{
		switch ($encoding) {
			case 'quoted-printable':
				$result = quoted_printable_decode($content);
			break;
			case 'base64':
				$result = base64_decode($content);
			break;
			default:
				$result = $content;
			break;
		}
		return $result;
	}
 
	/**
	 * This is where everything is done
	 */
	public function processMail()
	{
		if ($this->_mail instanceof Zend_Mail_Storage_Pop3 && $this->_mail->countMessages() > 0) {
			$messageNum = 0;
			foreach ($this->_mail as $message) {
				$messageNum++;
				$rawMail      = $this->_mail->getRawHeader($messageNum) . $this->_mail->getRawContent($messageNum);
				$received     = $message->received;
				$date         = date('Y-m-d H:i:s', strtotime($message->date));
				$messageId    = $message->headerExists('message-id') ? $message->getHeader('message-id') : null;
				//remove <> from message id
				$messageId    = (preg_match('|< (.*?)>|', $messageId, $regs)) ? $regs[1] : $messageId;
				$inReplyTo    = $message->headerExists('in-reply-to') ? $message->getHeader('in-reply-to') : null;
				//remove <> from in-reply-to
				$inReplyTo    = (preg_match('|< (.*?)>|', $inReplyTo, $regs)) ? $regs[1] : $inReplyTo;
				$references   = $message->headerExists('References')  ? $message->getHeader('References') : null;
				//remove <> from references
				$references   = (preg_match('|< (.*?)>|', $references, $regs)) ? $regs[1] : $references;
				$from         = $message->from;
				$subject      = $message->subject;
				$to           = $message->to;
				$plainContent = null;
				$htmlContent  = null;
				$attachments = array();
 
				/**
				 * Check if the message has multiple parts
				 */
		        if ($message->isMultipart()) {
					/**
					 * We have a multipart message
					 * lets extract the plain content,
					 * html content, and attachments
					 */
					foreach (new RecursiveIteratorIterator($message) as $part) {
						try {
							switch (strtok($part->contentType, ';')) {
								case 'text/plain':
									$plainContent = $this->_contentDecoder($part->getHeader('content-transfer-encoding'), $part->getContent());
								break;
								case 'text/html':
									$htmlContent = $this->_contentDecoder($part->getHeader('content-transfer-encoding'), $part->getContent());
								break;
								default: //attachment handle
									$type       = strtok($part->contentType, ';');
									$fileName   = $part->getHeader('content-description');
									$attachment = $this->_contentDecoder($part->getHeader('content-transfer-encoding'), $part->getContent());
									$attachments[] = array(
													   'file_name' => $fileName,
													   'type'      => $type,
													   'content'	=> $attachment);
								break;
							}
						} catch (Zend_Mail_Exception $e) {
							echo "$e \n";
						}
					}
				} else {
					$plainContent = $message->getContent();
				}
				$this->_inbox[] = array('messageNumber' => $messageNum,
									    'rawMail'       => $rawMail,
										'received'		=> $received,
										'date'			=> $date,
										'messageId'		=> $messageId,
										'inReplyTo'		=> $inReplyTo,
										'references'	=> $references,
										'from'			=> $from,
										'subject'		=> $subject,
										'to'			=> $to,
										'plainContent'	=> $plainContent,
										'htmlContent'	=> $htmlContent,
										'attachments'	=> $attachments);
			}
		} else {
			$this->_inbox = false;
		}
	}
	public function getInbox()
	{
		return $this->_inbox;
	}
}

My fetch class does everything on instantiation, and it will have all the mails retreived, so for example if I need to get all messages I can do this:

< ?php
include_once 'mailFetcher.php';
 
$inbox = new mailFetcher();
print_r($inbox->getInbox());

And this would be the result:

Array
(
    [0] => Array
        (
            [messageNumber] => 1
            [rawMail] => Received: from gate55.gate.iad.mailserver.com (11.1.111.1) by
 IAD2HUB01.mex02.mailserver.com (111.11.11.65) with Microsoft SMTP Server (TLS) id
 8.2.247.2; Wed, 9 Jun 2010 17:56:16 -0400
Received: from mail-yw0-f186.google.com (mail-yw0-f186.google.com
 [111.11.111.186])	by gate55.gate.iad.mailserver.com (SMTP Server) with ESMTP id
 B1F6E31D0171	for <asdfasdf @ivanvillareal.com>; Wed,  9 Jun 2010
 17:56:15 -0400 (EDT)
Received: by ywh16 with SMTP id 16so5309053ywh.32        for
 </asdfasdf><asdfasdf @ivanvillareal.com>; Wed, 09 Jun 2010 14:56:15 -0700 (PDT)
Received: by 10.111.111.111 with SMTP id jz1mr465966qcb.170.1276120573865;
 	Wed, 09 Jun 2010 14:56:13 -0700 (PDT)
Received: by 11.111.111.11 with HTTP; Wed, 9 Jun 2010 14:56:13 -0700 (PDT)
From: Ivan Villareal <ivaano @gmail.com>
To: "asdfasdf@ivanvillareal.com" <asdfasdf @ivanvillareal.com>
Date: Wed, 9 Jun 2010 17:56:13 -0400
Subject: attachment test
Thread-Topic: attachment test
Thread-Index: AcsIHpXuE+vWJJMfTGyqikgD2kYkng==
Message-ID: <aanlktingkmpbkefog5kxxoq8wrib7tj1pt1rsy -1ug-1@mail.gmail.com>
Accept-Language: en-US
Content-Language: en-US
X-MS-Exchange-Organization-AuthAs: Anonymous
X-MS-Exchange-Organization-AuthSource: IAD2HUB01.mex02.mailserver.com
X-MS-Has-Attach: yes
X-MS-TNEF-Correlator:
x-virus-scanned: OK, catchall
x-originating-ip: [111.11.111.186]
dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed;        d=gmail.com;
 s=gamma;
        h=domainkey-signature:mime-version:received:received:date:message-id
         :subject:from:to:content-type;
        bh=IvMOHmKRabcJ2PrUHPHB/NbNpgQubvvgGprC6gtDY9E=;
        b=cA5Pjycedt9Pylic7CTk4HCF6HXV9eEFpr086KwcMepGKJEv4DWU6d4iFt4Gp7R42V
         +4rVmrmwj2j9yj1vbEUqVMI6/m+Kkwt1r+MAtN/0qZsvEaVBBbbjTBxFLO9cQ7xlaSSm
         eGTHv9mR0qCcBZGLOVFeWUNiYDkhY2F0eDUbU=
domainkey-signature: a=rsa-sha1; c=nofws;        d=gmail.com; s=gamma;
        h=mime-version:date:message-id:subject:from:to:content-type;
        b=VKdlRSfBz/Swij0xE0c7Su8TOwcc2YGmw0K8dvVxoS9TJf0p8nIqtR6nQtmKqabSu4
         g2ALFFHXuVOhGpP+JdvI3wQJ1k9N5EZhcWtSRECrikOlLnaDA8/4z3SYckY6hs7Q+KIe
         qG0IbY+QkuZh7yymcyAN5omTaFDFT2GIPs+1c=
x-orig-to: catchall@ivanvillareal.com
Content-Type: multipart/mixed;
	boundary="_004_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_"
MIME-Version: 1.0
 
--_004_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_
Content-Type: multipart/alternative;
	boundary="_000_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_"
 
--_000_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
 
amhnamhnamhnDQo=
 
--_000_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64
 
amhnamhnamhnDQo=
 
--_000_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_--
 
--_004_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_
Content-Type: image/jpeg; name="2010-05-28-112655.jpg"
Content-Description: 2010-05-28-112655.jpg
Content-Disposition: attachment; filename="2010-05-28-112655.jpg"; size=15004;
	creation-date="Wed, 09 Jun 2010 17:56:16 GMT";
	modification-date="Wed, 09 Jun 2010 17:56:16 GMT"
Content-Transfer-Encoding: base64
 
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
gq4UlFJmmKwtHakzS0DsMNFLikIxQAUmKKM0AFLSUtABRRRQAlFGeaKACiikouAtGaKPrQAmaKDS
4oASgClxRQKwUUUlAxaKKM0AFBNFGM0AGalHzIKiIp6HgigQuKKKKQyZDlaJAcU2I09+VP0qWSRK
R0zTGXBpuec1IDvX3qihqNhhV5WG0Vn9DUocgUMTJpyCpIqsKezZXmoqENDqQ0dqBmmMBS0UmKAF
oFJS0AJ3oIpQKQk0AAp4JxTBTxQwYE0oFNNOU8UhCkDGKaRin0EZoEiLIpcUuzuKMUyrje9FKQet
J2oGf//Z
 
--_004_AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy1ug1mailgmailcom_--
 
            [received] => from gate55.gate.iad.mailserver.com (11.1.111.1) by IAD2HUB01.mex02.mailserver.com (111.11.11.15) with Microsoft SMTP Server (TLS) id 1.1.147.2; Wed, 9 Jun 2010 17:56:16 -0400
from mail-yw0-f186.google.com (mail-yw0-f186.google.com [209.85.211.186])	by gate55.gate.iad.mailserver.com (SMTP Server) with ESMTP id B1F6E31D0171	for <asdfasdf @ivanvillareal.com>; Wed,  9 Jun 2010 17:56:15 -0400 (EDT)
by ywh16 with SMTP id 16so5309053ywh.32        for </asdfasdf><asdfasdf @ivanvillareal.com>; Wed, 09 Jun 2010 14:56:15 -0700 (PDT)
by 10.229.233.193 with SMTP id jz1mr465966qcb.170.1276120573865; Wed, 09 Jun 2010 14:56:13 -0700 (PDT)
by 10.229.192.82 with HTTP; Wed, 9 Jun 2010 14:56:13 -0700 (PDT)
            [date] => 2010-06-09 14:56:13
            [messageId] => AANLkTingkMPbKeFog5kxXoq8WRib7tJ1pT1Rsy-1ug-1@mail.gmail.com
            [inReplyTo] => 
            [references] => 
            [from] => Ivan Villareal <ivaano @gmail.com>
            [subject] => attachment test
            [to] => "asdfasdf@ivanvillareal.com" <asdfasdf @ivanvillareal.com>
            [plainContent] => jhgjhgjhg
 
            [htmlContent] => jhgjhgjhg
 
            [attachments] => Array
                (
                    [0] => Array
                        (
                            [file_name] => 2010-05-28-112655.jpg
                            [type] => image/jpeg
                        )
 
                )
 
        )
 
)</asdfasdf></ivaano></asdfasdf></aanlktingkmpbkefog5kxxoq8wrib7tj1pt1rsy></asdfasdf></ivaano></asdfasdf>

From this point I can iterate the inbox easily saving the email results or applying other logic to it,

PHP cross domain ajax Proxy

March 19th, 2010 Ivan Villareal No comments

I received a javascript application, that made cross domain calls to a webservice using the flensed library, this was pretty neat, but filling the dropdown boxes was very slow. Not to mention unnecessary, because I was going to embed the dropdown values into this modal window.

What I did was to refactor the javascript app, into php code to fill the values, and left the important webservice requests alone, I didn’t want to use the flXHR library, because the widget was so simple, so what I did was a php json-rpc proxy client, winch its work would be to post the data received from the client to a remote webservice.

I’m using Zend_Json to encode/decode json, because the php version on production is 5.1, and the php json extensions are not available.

First I create an object that will hold the data to be sent.

01
$re = new stdClass();
02
$re->brand_id  = $_POST['brand_id'];
03
$names         = $_POST['domains'];
04
 
05
$domains = explode(",", $names);
06
$filteredDomains = array();
07
foreach ($domains as $domain) {
08
 $domainParts = parse_url($domain);
09
 if (isset($domainParts['host']) && $domainParts['host'] != '') {
10
 $filteredDomains[] = $domainParts['host'];
11
 }
12
}
13
$re->domains   = $filteredDomains;

That was simple, I didn’t have to worry about filtering the user input, because the webservice will take care of that, the only thing I do, is  create an array of domains, with has only the host part.

after I have my Object ready I encode it as a json string, open a socket and make the request, here is how I did it:

01
$request = Zend_Json::encode($re);
02
$opts = array ('http' => array (
03
    'method'  => 'POST',
04
    'header'  => 'Content-type: application/json',
05
    'content' => $request
06
    ));
07
$context  = stream_context_create($opts);
08
$conection = $fp = fopen($url, 'r', false, $context);
09
if ($conection) {
10
 $reply = '';
11
 while($row = fgets($fp)) {
12
 $reply.= trim($row)."\n";
13
}
14
$reply = Zend_Json::decode($reply);

Pretty simple no?

Sync mysql tables from one db to another with php

February 16th, 2010 Ivan Villareal No comments

I needed a process to move a table from one database to another, the databases are on separate servers, so renaming the table will not work, I did a little research and found this Table Syncer it seemed fine, the problem is that it was on ruby gem, and I said the problem because the server where this will be running don’t have this installed.

So instead of doing more research I spent that time developing my own php class to sync two tables on different server, I have little time to create this so I’m re-using a class I already did for handling several databases and it already has some useful methods, right now its 3:12pm I plan to finish this in 30 minutes lets see how it goes.

In the end I spent about an hour but I have a working file that can put in a cron job to sync the table on a regular basis.

I’ve changed the way I fetch the entire result, to avoid having problems exhausting the dedicated php memory with large arrays, instead I’m fetching one row at a time, another problem I had, was that the null values came blank so, when I was inserting on a unique index, I had an error, to avoid this I remove the empty values from the insert, and use the default table value instead, this results in a bit different tables Null instead of blanks, but because this isn’t important I didn’t want to spend more with this.

The final file, contains the db class and the sync class, and here it is:

< ?php
 
/**
* The purpose of this file is to sync
* tables between 2 databases
*/
 
class tableSync {
    private $_sourceDbUser = 'ivan';
    private $_sourceDbPass = 'pass';
    private $_sourceDbName = 'bounty';
    private $_sourceDbHost = 'localhost';
 
    private $_targetDbUser = 'ivan';
    private $_targetDbPass = 'pass';
    private $_targetDbName = 'testing';
    private $_targetDbHost = 'localhost';
 
    private $_sourceDb, $_targetDb, $_primaryKey, $_table;
 
    public function __construct($table)
    {
        $this->_sourceDb = new Db($this->_sourceDbUser, $this->_sourceDbPass, $this->_sourceDbName, $this->_sourceDbHost);
        $this->_targetDb = new Db($this->_targetDbUser, $this->_targetDbPass, $this->_targetDbName, $this->_targetDbHost);
        $this->_table = $table;
        $this->begin();
    }
 
    public function begin()
    {
      //Check that the table exists
        $sql = 'SHOW TABLES';
        $tbl = $this->_targetDb->fetchAssoc($sql);
 
        if (!in_array($this->_table, current($tbl))) {
                //create the table
                $sql = "SHOW CREATE TABLE `".$this->_table."`";
                $tbl = $this->_sourceDb->fetchAssoc($sql);
                $createQry = $tbl[0]['Create Table'];
                $res = $this->_targetDb->query($createQry);
        }
 
        //Get The primary Key
        $sql     = "SHOW indexes FROM ".$this->_table." WHERE Key_name = 'PRIMARY'";
        $indexes = $this->_sourceDb->fetchAssoc($sql);
        $this->_primaryKey = $indexes[0]['Column_name'];
        //Query source  table
        $sql     = 'SELECT * FROM '.$this->_table;
        $rowset  = $this->_sourceDb->query($sql);
        while ($row = mysql_fetch_assoc($rowset)) {
            //remove empty fields
            $newRow = array();
            foreach ($row as $field => $value) {
                if ($value != '') {
                    $newRow[$field] = $value;
                }
            }
            if ($this->_primaryKey != '') {
                echo "Inserting row ".$row[$this->_primaryKey] . "\n";
                $res = $this->_targetDb->insertUpdate($this->_table, $newRow, $this->_primaryKey, $row[$this->_primaryKey]);
            } else {
                $res = $this->_targetDb->queryInsert($this->_table, $newRow);
            }
        }
    }
}
 
class Db
{
	private	$_link;
	private $_affectedRows;
	private $_lastQueryStatus;
 
	/**
	* Instantiate the object
	**/
	public function __construct( $user, $pass, $dbName, $host = 'localhost')
	{
            $this->_link = mysql_connect($host, $user, $pass, true);
            mysql_select_db($dbName, $this->_link) or die('Could not select database');
            if (mysql_error()) {
                    printf("Connect failed: %s\n", mysql_error());
                    exit();
            } else {
                $sql = "SET NAMES `utf8`";
                mysql_query($sql, $this->_link);
                mysql_query("SET CHARACTER SET 'utf8';", $this->_link);
            }
	}
 
        public function query($sql)
	{
            $this->_lastQueryStatus = @mysql_query($sql, $this->_link) or die('Query failed: ' . mysql_error() . '<br /> SQL: '. $sql);
            if (!$this->_lastQueryStatus) {
                    $this->error("<b>MySQL Query fail:</b> $sql");
            }
            $this->_affectedRows    = @mysql_affected_rows();
            return $this->_lastQueryStatus;
	}
 
        public function fetchAssoc($sql)
	{
            $result = $this->query($sql);
            $table = array();
            while ($row = mysql_fetch_assoc($result)) {
                    $table[] = $row;
            }
            return $table;
	}
 
        public function escape($string)
	{
		if(get_magic_quotes_gpc()) $string = stripslashes($string);
		return mysql_real_escape_string($string);
	}
 
        public function fetchField($table, $field, $where = '1')
	{
	    $sql = "SELECT `$field` FROM `$table` WHERE $where";
	    $result = $this->query($sql);
	    $field = mysql_fetch_row($result);
	    return $field[0];
	}
 
        public function insertUpdate($table, $data, $field, $uniqueValue)
	{
	    $where = is_int($uniqueValue) ? "$field = $uniqueValue" : "$field = '".$this->escape($uniqueValue)."'";
	    $e = $this->fetchField($table, $field, $where);
	    if ($e) {
	        $res = $this->queryUpdate($table, $data, $where);
	    } else {
	        $res = $this->queryInsert($table, $data);
	    }
	    return $res;
	}
 
        public function queryInsert($table, $data)
	{
            $q="INSERT INTO `".$table."` ";
            $v='';
            $n='';
 
            foreach($data as $key=>$val) {
                    $n.="`$key`, ";
                    if(strtolower($val)=='null') $v.="NULL, ";
                    elseif(strtolower($val)=='now()') $v.="NOW(), ";
                    elseif(strtolower($val)=='utc_timestamp()') $v.="UTC_TIMESTAMP(), ";
                    else $v.= "'".$this->escape($val)."', ";
            }
            $q .= "(". rtrim($n, ', ') .") VALUES (". rtrim($v, ', ') .");";
            if($this->query($q)){
                    $result = mysql_insert_id();
            } else {
                    $result = false;
            }
            return $result;
	}
 
        public function queryUpdate($table, $data, $where='1')
        {
            $q="UPDATE `".$table."` SET ";
 
            foreach($data as $key=>$val) {
                if(strtolower($val)=='null') $q.= "`$key` = NULL, ";
                elseif(strtolower($val)=='now()') $q.= "`$key` = NOW(), ";
                else $q.= "`$key`='".$this->escape($val)."', ";
            }
            $q = rtrim($q, ', ') . ' WHERE '.$where.';';
 
            return $this->query($q);
        }
}
 
//Instantiate the tableSync sending the table name I want to sync
$sync = new tableSync('tod_whois_raider');

Categories: Development, PHP Tags: , ,

Decrypting SourceCop php files

January 30th, 2010 Ivan Villareal 11 comments

Every once in a while, I receive code that is encrypted using one of many php encoder software out there, so when I face this situation and if the project is worth it, I start playing around with the encrypted files to see how the encoding algorithm works, so far I’ve been able to successful decrypt files encoded with Zend, and ioncube, I don’t remember the versions of the encoders but I remember that the latter one took me some time, but I did it.

I must say that decoding files also becomes a personal challenge, it is like a hobby when I have the time to play with it.

 Yesterday I received a couple of files encoded with an unknown encoder for me, it didn’t require any php modification or extension install, so I tough that it would be easy to break it, because at some point the code must be evaluated, so after I opened the zip file, I noticed a folder called “scopbin“, that contained only 1 php file named “911006.php“, the two encoded files were  including this file so I assumed that this is were the decryption logic had to be.

I was exhausted by a long working day, and when I got this files and saw that they were encrypted I placed them in my laptop for later analysis. This analysis was done while  I was waiting for the local news, I didn’t research the encoding, or did  anything that give me some pointers, I just started to playing around with the code to see how far  could I get.

My objective this time was getting this files decrypted, and not analysing the steps of the algorithm, so with this in mind, this is what I did:

This was the original “911006.php” file:

< ?php ini_set('include_path',dirname(__FILE__));function A4540acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){return $Xew6e79316561733d64abdf00f8e8ae48;}function b5434f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){return $Xew6e79316561733d64abdf00f8e8ae48;}function c43dsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){return $Xew6e79316561733d64abdf00f8e8ae48;}function Xdsf0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){return $Xew6e79316561733d64abdf00f8e8ae48;}function y0666f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){$x0b43c25ccf2340e23492d4d3141479dc='';$x71510c08e23d2083eda280afa650b045=0;$x16754c94f2e48aae0d6f34280507be58=strlen($x897356954c2cd3d41b221e3f24f99bba);$x7a86c157ee9713c34fbd7a1ee40f0c5a=hexdec('&H'.substr($x276e79316561733d64abdf00f8e8ae48,0,2));for($x1b90e1035d4d268e0d8b1377f3dc85a2=2;$x1b90e1035d4d268e0d8b1377f3dc85a2<strlen($x276e79316561733d64abdf00f8e8ae48);$x1b90e1035d4d268e0d8b1377f3dc85a2+=2){$xe594cc261a3b25a9c99ec79da9c91ba5=hexdec(trim(substr($x276e79316561733d64abdf00f8e8ae48, $x1b90e1035d4d268e0d8b1377f3dc85a2, 2)));$x71510c08e23d2083eda280afa650b045=(($x71510c08e23d2083eda280afa650b045<$x16754c94f2e48aae0d6f34280507be58)?$x71510c08e23d2083eda280afa650b045 + 1:1);$xab6389e47b1edcf1a5267d9cfb513ce5=$xe594cc261a3b25a9c99ec79da9c91ba5 ^ ord(substr($x897356954c2cd3d41b221e3f24f99bba, $x71510c08e23d2083eda280afa650b045-1, 1));if($xab6389e47b1edcf1a5267d9cfb513ce5<=$x7a86c157ee9713c34fbd7a1ee40f0c5a)$xab6389e47b1edcf1a5267d9cfb513ce5=255+$xab6389e47b1edcf1a5267d9cfb513ce5-$x7a86c157ee9713c34fbd7a1ee40f0c5a;else $xab6389e47b1edcf1a5267d9cfb513ce5=$xab6389e47b1edcf1a5267d9cfb513ce5-$x7a86c157ee9713c34fbd7a1ee40f0c5a;$x0b43c25ccf2340e23492d4d3141479dc=$x0b43c25ccf2340e23492d4d3141479dc.chr($xab6389e47b1edcf1a5267d9cfb513ce5);$x7a86c157ee9713c34fbd7a1ee40f0c5a=$xe594cc261a3b25a9c99ec79da9c91ba5;} return $x0b43c25ccf2340e23492d4d3141479dc;}function f5434f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function j43dsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function hdsf0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function tr5434f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function f0666f0acdeed38d4cd9084ade1739498($x) { return implode('',file($x));} function g0666f0acdeed38d4cd9084ade1739498($s){return (strstr($s,'echo')==false?(strstr($s,'print')==false)?(strstr($s,'sprint')==false)?(strstr($s,'sprintf')==false)?false:exit():exit():exit():exit());}function hyr3dsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function uygf0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function drfg34f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function jhkgvdsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;}function yrdhhdacdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba,$x276e79316561733d64abdf00f8e8ae48){if(file_exists($x456e79316561733d64abdf00f8e8ae48)){unlink($x456e79316561733d64abdf00f8e8ae48);};return $Xew6e79316561733d64abdf00f8e8ae48;} ini_set('include_path','.');?>

I’ve used a code formatter to make the code  more readable:

ivan@mini:/var/www/copdecrypt/scopbin$ phpCB --space-after-if  \
--space-after-switch                                           \
--space-after-while                                            \
--space-before-srt-angle-bracket                               \
--space-after-end-angle-bracket                                \
--glue-amperscore                                              \
--change-shell-comment-to-double-slashes-comment               \
--force-large-php-code-tag                                     \
--force-true-false-null-contant-lowercase                      \
--align-equal-statements                                       \
--comment-rendering-style PEAR                                 \
--equal-align-position 50                                      \
--padding-char-count 4                                         \
911006.php

And this was the result:

< ?php
ini_set('include_path', dirname(__FILE__));
function A4540acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function b5434f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function c43dsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function Xdsf0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function y0666f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    $x0b43c25ccf2340e23492d4d3141479dc = '';
    $x71510c08e23d2083eda280afa650b045 = 0;
    $x16754c94f2e48aae0d6f34280507be58 = strlen($x897356954c2cd3d41b221e3f24f99bba);
    $x7a86c157ee9713c34fbd7a1ee40f0c5a = hexdec('&H' . substr($x276e79316561733d64abdf00f8e8ae48, 0, 2));
    for($x1b90e1035d4d268e0d8b1377f3dc85a2 = 2;$x1b90e1035d4d268e0d8b1377f3dc85a2 < strlen($x276e79316561733d64abdf00f8e8ae48);$x1b90e1035d4d268e0d8b1377f3dc85a2 += 2) {
        $xe594cc261a3b25a9c99ec79da9c91ba5 = hexdec(trim(substr($x276e79316561733d64abdf00f8e8ae48, $x1b90e1035d4d268e0d8b1377f3dc85a2, 2)));
        $x71510c08e23d2083eda280afa650b045 = (($x71510c08e23d2083eda280afa650b045 < $x16754c94f2e48aae0d6f34280507be58)?$x71510c08e23d2083eda280afa650b045 + 1:1);
        $xab6389e47b1edcf1a5267d9cfb513ce5 = $xe594cc261a3b25a9c99ec79da9c91ba5 ^ ord(substr($x897356954c2cd3d41b221e3f24f99bba, $x71510c08e23d2083eda280afa650b045-1, 1));
        if ($xab6389e47b1edcf1a5267d9cfb513ce5 <= $x7a86c157ee9713c34fbd7a1ee40f0c5a)$xab6389e47b1edcf1a5267d9cfb513ce5 = 255 + $xab6389e47b1edcf1a5267d9cfb513ce5 - $x7a86c157ee9713c34fbd7a1ee40f0c5a;
        else $xab6389e47b1edcf1a5267d9cfb513ce5 = $xab6389e47b1edcf1a5267d9cfb513ce5 - $x7a86c157ee9713c34fbd7a1ee40f0c5a;
        $x0b43c25ccf2340e23492d4d3141479dc = $x0b43c25ccf2340e23492d4d3141479dc . chr($xab6389e47b1edcf1a5267d9cfb513ce5);
        $x7a86c157ee9713c34fbd7a1ee40f0c5a = $xe594cc261a3b25a9c99ec79da9c91ba5;
    } 
    return $x0b43c25ccf2340e23492d4d3141479dc;
} 
function f5434f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function j43dsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function hdsf0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function tr5434f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function f0666f0acdeed38d4cd9084ade1739498($x) {
    return implode('', file($x));
} 
function g0666f0acdeed38d4cd9084ade1739498($s) {
    return (strstr($s, 'echo') == false?(strstr($s, 'print') == false)?(strstr($s, 'sprint') == false)?(strstr($s, 'sprintf') == false)?false:exit():exit():exit():exit());
} 
function hyr3dsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function uygf0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function drfg34f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function jhkgvdsd0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
function yrdhhdacdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
    if (file_exists($x456e79316561733d64abdf00f8e8ae48)) {
        unlink($x456e79316561733d64abdf00f8e8ae48);
    } ;
    return $Xew6e79316561733d64abdf00f8e8ae48;
} 
ini_set('include_path', '.');
 

After a quick review of this file, I saw that it had several functions that had same logic, return an unknow variable or delete the file that this unknown variable had, appart from all this “useless” functions I quickly found what appeared to be the decryption function this was the function named y0666f0acdeed38d4cd9084ade1739498 with this information I headed to check one of the encrypted files, and this is how it looked:

< ?php if(!function_exists('findsysfolder')){function findsysfolder($fld){$fld1=dirname($fld);$fld=$fld1.'/scopbin';clearstatcache();if(!is_dir($fld))return findsysfolder($fld1);else return $fld;}}require_once(findsysfolder(__FILE__).'/911006.php');$REXISTHECAT4FBI='FE50E574D754E76AC679F242F450F768FB5DCB77F34DE341 660C280D176E374DE7FB3B090A782B6B68DBC97BEAD93B681C452F25BE26';g0666f0acdeed38d4cd9084ade1739498(f0666f0acdeed38d4cd9084ade1739498(__FILE__));$REXISTHEDOG4FBI='9CEF6BE117B329ADFC4560538EBF16BB6DAD1748FE354E8EDA7AABFA376EB6938496F43560E4123D85D272E342E363FD51F3181763A3F623 660B6E2369243EE5781CD76A133E272E37DACA198968397F150425B4326A126CD64F051F35287DE7BD3 5354276B880BDEF525247533610 64282D07BA63861F81DB715C115BC1BD57FC5D9C8 225D2 A F177EDC7EA026A7E74D37AC28A125D1B8F73B63C6D1C3A1E137639BEECEDACFDBBD9F8D948CE93D6FCDCDD8CCA98B36AA21A08B8BD87FD8 15143C2C2D37593B82857516FC9ABF9237BDEC9DBB9F92F7BDEB8EE3B6AEA153C9DF3 A2CAE2CD218B1E566C0D274D6 F32DC2A E20 512 062A2F72C 96FB9ED3B6FC9ABF927A34985CAB5D3 65D89B315B3E61076D8 E4488B2127FCEF82C78DDBBED3A6FBB7FCEEACEE04453412363B6E246F05086C7 52E C408CC263E078A53461E0 331B71EB81DC475DB6CAC9531914393D4 22AC9C3D7CE7194438AD638 03D6FCDCDD8CCA98F99211B1177D5C7DEC6A3F427 5 510 461C7D1C51AB492F850FA56FE445EC0154885BDACDC 819BD76A72A419A4D859CFE5A5268CDABFD2A7FAB8DEF227BA3869183E12277A386E03763B6E241F75282CDBFCA187ECE74D7 D1D4881D3C7432177D4 E3F83DA54417EAA8FE93C68BDE94C2E7CA5FD5B4C5E3C9993A98CEA3D69BCE84F2D989C9EEECFDDBFFF15 164C2D471D3 228D3 51CBA75D4 A3C85C1 4618EC5 E6BE91FCD F4D87BE F 56BFB5BFE2A3EA923BDDDBB9D26BE13CD 41F6E584D593C1A C18 D19D29D958C94F12577D5D5C0D4B19781958094F21EB6EF20CC77D87CD0CDC57FA13D8484F61076D47ED5 366F521A6FA2FEFBAF22772A680E23168B0958290F23366B297F12470A5F1543664EF6DA42DAD5E5EB718C569EA2C5F8AE81BBF16BE489E3EE13D7FBD98FE297DA8FC5B396BB2EA4E594B2969D3C7689230A1F4441763B1E83114 31173B3E6331670A6F22672D4B6E43C64C1D6C475FA5AFB2BDF36A83F9F55F8 62A C69BEEC4F4F5A4E2B D1B F1A E68CAD86F44 B1C E6CACF92E B6DDCDDD26437 3';$REXISTHECAT4FBI='94CD76CD371C5A7BC70C186E779C293B9B49BACA5A781A6'; eval(y0666f0acdeed38d4cd9084ade1739498('4EF6454FB298E72B 5',$REXISTHEDOG4FBI));?>

Again I used the code beautifier  to make this file more readable:

ivan@mini:/var/www/copdecrypt$ phpCB --space-after-if  \
--space-after-switch                                           \
--space-after-while                                            \
--space-before-srt-angle-bracket                               \
--space-after-end-angle-bracket                                \
--glue-amperscore                                              \
--change-shell-comment-to-double-slashes-comment               \
--force-large-php-code-tag                                     \
--force-true-false-null-contant-lowercase                      \
--align-equal-statements                                       \
--comment-rendering-style PEAR                                 \
--equal-align-position 50                                      \
--padding-char-count 4                                         \
test.php

And this was the result:
< ?php if (!function_exists('findsysfolder')) {
    function findsysfolder($fld) {
        $fld1 = dirname($fld);
        $fld = $fld1 . '/scopbin';
        clearstatcache();
        if (!is_dir($fld))return findsysfolder($fld1);
        else return $fld;
    } 
} 
require_once(findsysfolder(__FILE__) . '/911006.php');
$REXISTHECAT4FBI = 'FE50E574D754E76AC679F242F450F768FB5DCB77F34DE341 660C280D176E374DE7FB3B090A782B6B68DBC97BEAD93B681C452F25BE26';
g0666f0acdeed38d4cd9084ade1739498(f0666f0acdeed38d4cd9084ade1739498(__FILE__));
$REXISTHEDOG4FBI = '9CEF6BE117B329ADFC4560538EBF16BB6DAD1748FE354E8EDA7AABFA376EB6938496F43560E4123D85D272E342E363FD51F3181763A3F623 660B6E2369243EE5781CD76A133E272E37DACA198968397F150425B4326A126CD64F051F35287DE7BD3 5354276B880BDEF525247533610 64282D07BA63861F81DB715C115BC1BD57FC5D9C8 225D2 A F177EDC7EA026A7E74D37AC28A125D1B8F73B63C6D1C3A1E137639BEECEDACFDBBD9F8D948CE93D6FCDCDD8CCA98B36AA21A08B8BD87FD8 15143C2C2D37593B82857516FC9ABF9237BDEC9DBB9F92F7BDEB8EE3B6AEA153C9DF3 A2CAE2CD218B1E566C0D274D6 F32DC2A E20 512 062A2F72C 96FB9ED3B6FC9ABF927A34985CAB5D3 65D89B315B3E61076D8 E4488B2127FCEF82C78DDBBED3A6FBB7FCEEACEE04453412363B6E246F05086C7 52E C408CC263E078A53461E0 331B71EB81DC475DB6CAC9531914393D4 22AC9C3D7CE7194438AD638 03D6FCDCDD8CCA98F99211B1177D5C7DEC6A3F427 5 510 461C7D1C51AB492F850FA56FE445EC0154885BDACDC 819BD76A72A419A4D859CFE5A5268CDABFD2A7FAB8DEF227BA3869183E12277A386E03763B6E241F75282CDBFCA187ECE74D7 D1D4881D3C7432177D4 E3F83DA54417EAA8FE93C68BDE94C2E7CA5FD5B4C5E3C9993A98CEA3D69BCE84F2D989C9EEECFDDBFFF15 164C2D471D3 228D3 51CBA75D4 A3C85C1 4618EC5 E6BE91FCD F4D87BE F 56BFB5BFE2A3EA923BDDDBB9D26BE13CD 41F6E584D593C1A C18 D19D29D958C94F12577D5D5C0D4B19781958094F21EB6EF20CC77D87CD0CDC57FA13D8484F61076D47ED5 366F521A6FA2FEFBAF22772A680E23168B0958290F23366B297F12470A5F1543664EF6DA42DAD5E5EB718C569EA2C5F8AE81BBF16BE489E3EE13D7FBD98FE297DA8FC5B396BB2EA4E594B2969D3C7689230A1F4441763B1E83114 31173B3E6331670A6F22672D4B6E43C64C1D6C475FA5AFB2BDF36A83F9F55F8 62A C69BEEC4F4F5A4E2B D1B F1A E68CAD86F44 B1C E6CACF92E B6DDCDDD26437 3';
$REXISTHECAT4FBI = '94CD76CD371C5A7BC70C186E779C293B9B49BACA5A781A6';
eval(y0666f0acdeed38d4cd9084ade1739498('4EF6454FB298E72B 5', $REXISTHEDOG4FBI));

So what we have here is more obfuscated code, but a simple to understand, we have 2 variables and 3 functions, the variable that has the encrypted code should be the larger one so I'm assuming that is the "$REXISTHEDOG4FBI" variable, the other one apparently isn't used, so what I did at this point was to print the results of the evaluated function which corresponds to the function where the decrypt logic is (deofuscated):
function ($key, $program) {
    $result = '';
    $position = 0;
    $keyLength = strlen($key);
    $decValue = hexdec('&H' . substr($program, 0, 2));
 
    for($i = 2;$i < strlen($program);$i += 2) {
        $decProgram = hexdec(trim(substr($program, $i, 2)));
        $position   = (($position < $keyLength) ? $position + 1 : 1);
        $ascii = $decProgram^ ord(substr($key, $position-1, 1));
 
        if ($ascii <= $decValue) $ascii = 255 + $ascii - $decValue;
        else $ascii = $ascii - $decValue;
 
        $result   = $result . chr($ascii);
        $decValue = $decProgram;
    } 
    return $result;
} 

unfortunately printing the result didn't work, so I did a review to check why, and I found that the other 2 functions where the problem, let me explain what happens, first a call is made to
function f0666f0acdeed38d4cd9084ade1739498($x) {
 
    return implode('', file($x));
 
}

this function receives the name of the executing file (test.php in my case), read its content in an array, then glues all lines to create a 1 line string, without any new lines, then this result is passed to the following function:

function g0666f0acdeed38d4cd9084ade1739498($s) {
 
    return (strstr($s, 'echo') == false ? (strstr($s, 'print') == false) ? (strstr($s, 'sprint') == false) ? (strstr($s, 'sprintf') == false) ? false : exit() : exit() : exit() : exit());
 
} 

which are a series of nested ternary conditions, looking for the words "echo,print,sprint,sprintf", if any of this words are in the encrypted file, then the script simply exits, that's why I was unable to print the decrypted code after calling the decoding function, so simply avoiding the call to this function will fix the issue and I will get my decrypted code.
However, I didn't want to modify the original encrypted files, so a second approach I took was modifying the decryption function and echoing the output from there, so I've added a couple of lines (15 and 16) to the "y0666f0acdeed38d4cd9084ade1739498" function:

01
function y0666f0acdeed38d4cd9084ade1739498($x897356954c2cd3d41b221e3f24f99bba, $x276e79316561733d64abdf00f8e8ae48) {
02
    $x0b43c25ccf2340e23492d4d3141479dc = '';
03
    $x71510c08e23d2083eda280afa650b045 = 0;
04
    $x16754c94f2e48aae0d6f34280507be58 = strlen($x897356954c2cd3d41b221e3f24f99bba);
05
    $x7a86c157ee9713c34fbd7a1ee40f0c5a = hexdec('&H' . substr($x276e79316561733d64abdf00f8e8ae48, 0, 2));
06
    for($x1b90e1035d4d268e0d8b1377f3dc85a2 = 2;$x1b90e1035d4d268e0d8b1377f3dc85a2 < strlen($x276e79316561733d64abdf00f8e8ae48);$x1b90e1035d4d268e0d8b1377f3dc85a2 += 2) {
07
        $xe594cc261a3b25a9c99ec79da9c91ba5 = hexdec(trim(substr($x276e79316561733d64abdf00f8e8ae48, $x1b90e1035d4d268e0d8b1377f3dc85a2, 2)));
08
        $x71510c08e23d2083eda280afa650b045 = (($x71510c08e23d2083eda280afa650b045 < $x16754c94f2e48aae0d6f34280507be58)?$x71510c08e23d2083eda280afa650b045 + 1:1);
09
        $xab6389e47b1edcf1a5267d9cfb513ce5 = $xe594cc261a3b25a9c99ec79da9c91ba5 ^ ord(substr($x897356954c2cd3d41b221e3f24f99bba, $x71510c08e23d2083eda280afa650b045-1, 1));
10
        if ($xab6389e47b1edcf1a5267d9cfb513ce5 <= $x7a86c157ee9713c34fbd7a1ee40f0c5a)$xab6389e47b1edcf1a5267d9cfb513ce5 = 255 + $xab6389e47b1edcf1a5267d9cfb513ce5 - $x7a86c157ee9713c34fbd7a1ee40f0c5a;
11
        else $xab6389e47b1edcf1a5267d9cfb513ce5 = $xab6389e47b1edcf1a5267d9cfb513ce5 - $x7a86c157ee9713c34fbd7a1ee40f0c5a;
12
        $x0b43c25ccf2340e23492d4d3141479dc = $x0b43c25ccf2340e23492d4d3141479dc . chr($xab6389e47b1edcf1a5267d9cfb513ce5);
13
        $x7a86c157ee9713c34fbd7a1ee40f0c5a = $xe594cc261a3b25a9c99ec79da9c91ba5;
14
    } 
15
    echo $x0b43c25ccf2340e23492d4d3141479dc;
16
    die();
17
    return $x0b43c25ccf2340e23492d4d3141479dc;
18
} 

And voilà, I was able to see the source code :D , here is a screen shot of the decrypted source:

Source Cop Decrypted

So in short, just print the output of the decrypt function, and kill the script to get the decrypted code, I don't know if there are any other versions of the "911006.php" file, but I guess that the same logic applies.

Please remember that this isn't a how-to, it is just my experience dealing with this files, also don't use any of these information for any illegal purposes.

Categories: PHP Tags: , , , , ,