2024-05-11 17:47:33 +03:00
|
|
|
|
<?php
|
|
|
|
|
|
2024-05-11 18:42:44 +03:00
|
|
|
|
/*
|
|
|
|
|
* ****************************************************************
|
|
|
|
|
CREATE BY HoldFast
|
|
|
|
|
Андрей Рейгант
|
|
|
|
|
http://vk.com/holdfast
|
|
|
|
|
MBTEAM.RU
|
|
|
|
|
* ****************************************************************
|
2024-05-11 17:47:33 +03:00
|
|
|
|
Коды ответов:
|
2024-05-11 18:42:44 +03:00
|
|
|
|
-1: неверный BAS-файл
|
2024-05-11 17:47:33 +03:00
|
|
|
|
-2: файл нельзя декмопилировать, поскольку он обфусцирован
|
|
|
|
|
0: файл успешно обфусцирован
|
2024-05-11 18:42:44 +03:00
|
|
|
|
* ****************************************************************
|
|
|
|
|
Пример:
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
$bas = new BAS('Autorun.bas'); ///Открываем BAS
|
|
|
|
|
$code = $bas->decompile(); //$code - декомпилированный код BAS
|
|
|
|
|
echo $code;
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
$bas->obfuscation('newbas.bas'); //обфусцировать открытый BAS, и сохранить
|
|
|
|
|
его с именем newbas.bas
|
2024-05-11 17:47:33 +03:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class BAS {
|
|
|
|
|
|
|
|
|
|
public $file;
|
|
|
|
|
public $data;
|
|
|
|
|
|
|
|
|
|
function __construct($files) {
|
|
|
|
|
$this->file = $files;
|
|
|
|
|
$this->init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function init() {
|
|
|
|
|
$this->data = file_get_contents($this->file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function decompile() {
|
|
|
|
|
$ops = array(
|
2024-05-11 18:42:44 +03:00
|
|
|
|
" STOP ", " POP ", " RETURN ", " END ", " NEW ", " RUN ", " DIR ", " DEG ", " RAD ", " BYE ", " GOTO ",
|
|
|
|
|
" GOSUB ", " SLEEP ", " PRINT ", " REM ", " DIM ", " IF ", " THEN ", " CLS ", " PLOT ", " DRAWLINE ",
|
|
|
|
|
" FILLRECT ", " DRAWRECT ", " FILLROUNDRECT ", " DRAWROUNDRECT ", " FILLARC ",
|
|
|
|
|
" DRAWARC ", " DRAWSTRING ", " SETCOLOR ", " BLIT ", " FOR ", " TO ", " STEP ", " NEXT ", " INPUT ",
|
|
|
|
|
" LIST ", " ENTER ", " LOAD ", " SAVE ", " DELETE ", " EDIT ", " TRAP ", " OPEN ", " CLOSE ",
|
|
|
|
|
" NOTE ", " POINT ", " PUT ", " GET ", " DATA ", " RESTORE ", " READ ", "=", "<>", "<", "<=",
|
|
|
|
|
">", ">=", "(", ")", ",", "+", "-", "-", "*", "/", "^", " BITAND ", " BITOR ", " BITXOR ", " NOT ",
|
|
|
|
|
" AND ", " OR ", "SCREENWIDTH", "SCREENHEIGHT", " ISCOLOR ", " NUMCOLORS ", "STRINGWIDTH", "STRINGHEIGHT",
|
|
|
|
|
"LEFT$", "MID$", "RIGHT$", "CHR$", "STR$", "LEN", "ASC", "VAL", " UP ", " DOWN ", " LEFT ", " RIGHT ",
|
|
|
|
|
" FIRE ", " GAMEA ", " GAMEB ", " GAMEC ", " GAMED ", " DAYS ", " MILLISECONDS ",
|
|
|
|
|
" YEAR ", " MONTH ", " DAY ", " HOUR ", " MINUTE ", " SECOND ", " MILLISECOND ", "RND", " ERR ",
|
|
|
|
|
" FRE ", "MOD", "EDITFORM ", "GAUGEFORM ", "CHOICEFORM", "DATEFORM", "MESSAGEFORM",
|
|
|
|
|
"LOG", "EXP", "SQR", "SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN", "ABS", "=", "#", " PRINT ",
|
|
|
|
|
" INPUT ", ":", " GELGRAB ", " DRAWGEL ", " SPRITEGEL ", " SPRITEMOVE ", " SPRITEHIT ",
|
|
|
|
|
"READDIR$", "PROPERTY$", " GELLOAD ", " GELWIDTH", " GELHEIGHT", " PLAYWAV ", " PLAYTONE ",
|
|
|
|
|
" INKEY", "SELECT", "ALERT ", " SETFONT ", " MENUADD ", " MENUITEM", " MENUREMOVE ",
|
|
|
|
|
" CALL ", " ENDSUB ", " REPAINT", "SENDSMS ", " RAND", " ALPHAGEL ", " COLORALPHAGEL ", " PLATFORMREQUEST ", " DELGE L", " DELSPRITE ", "MKDIR"
|
2024-05-11 17:47:33 +03:00
|
|
|
|
);
|
2024-05-11 18:42:44 +03:00
|
|
|
|
///version of BAS
|
|
|
|
|
switch ($this->readInt($this->data)) {
|
|
|
|
|
case '4d420001':
|
|
|
|
|
$version = 1;
|
|
|
|
|
break;
|
|
|
|
|
case '4d420191':
|
|
|
|
|
$version = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$version = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ($version == 0) {
|
2024-05-11 17:47:33 +03:00
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
$isDIM = false;
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$varnum = hexdec($this->readShort($this->data)); ///number variable
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$varname = [];
|
|
|
|
|
$main = '';
|
2024-05-11 18:42:44 +03:00
|
|
|
|
for ($i = 0; $i < $varnum; $i++) { //read variable name
|
|
|
|
|
$num = hexdec($this->readShort($this->data)); ///name length
|
2024-05-11 17:47:33 +03:00
|
|
|
|
for ($ii = 0; $ii < $num; $ii++) {
|
|
|
|
|
$varname[$i] = $varname[$i] ?? '';
|
|
|
|
|
$varname[$i] .= substr($this->data, 0, 1);
|
|
|
|
|
$this->readByte($this->data);
|
|
|
|
|
}
|
2024-05-11 18:42:44 +03:00
|
|
|
|
/// end read variable name
|
|
|
|
|
$this->readByte($this->data); // variable type
|
|
|
|
|
}
|
|
|
|
|
//float
|
|
|
|
|
if ($version == 2) {
|
|
|
|
|
$floatnum = hexdec($this->readShort($this->data));
|
|
|
|
|
for ($i = 0; $i < $floatnum; $i++) {
|
|
|
|
|
$byte[3] = $this->readByte($this->data, false);
|
|
|
|
|
$byte[2] = $this->readByte($this->data, false);
|
|
|
|
|
$byte[1] = $this->readByte($this->data, false);
|
|
|
|
|
$byte[0] = $this->readByte($this->data, false);
|
|
|
|
|
$tfloat = unpack('f', $byte[0] . $byte[1] . $byte[2] . $byte[3]); //uncpack float
|
|
|
|
|
$float[$i] = round($tfloat[1], 7);
|
|
|
|
|
}
|
2024-05-11 17:47:33 +03:00
|
|
|
|
}
|
2024-05-11 18:42:44 +03:00
|
|
|
|
|
|
|
|
|
$codeln = hexdec($this->readShort($this->data));
|
2024-05-11 17:47:33 +03:00
|
|
|
|
if ($codeln != strlen($this->data)) {
|
|
|
|
|
$this->init();
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
2024-05-11 18:42:44 +03:00
|
|
|
|
|
|
|
|
|
///read code
|
2024-05-11 17:47:33 +03:00
|
|
|
|
while (strlen($this->data) > 0) {
|
|
|
|
|
$line = "";
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$line .= hexdec($this->readShort($this->data)); //write number of line
|
|
|
|
|
$lineS = hexdec($this->readByte($this->data)); //length line
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$isl = 1;
|
|
|
|
|
unset($lims);
|
2024-05-11 18:42:44 +03:00
|
|
|
|
for ($ii = 0; $ii < $lineS - 4; $ii++) { ///read operators
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$lims[$ii] = $this->readByte($this->data);
|
|
|
|
|
}
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$cur = 0; //position of read
|
|
|
|
|
while ($cur < count($lims)) { //decompilation start
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$opType = $lims[$cur];
|
|
|
|
|
$cur++;
|
2024-05-11 18:42:44 +03:00
|
|
|
|
if (hexdec($opType) == 0xfc) { /// variable
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$varNum = hexdec($lims[$cur]);
|
|
|
|
|
|
|
|
|
|
$limsIndex = $cur - 2;
|
|
|
|
|
if (array_key_exists($limsIndex, $lims) && hexdec($lims[$limsIndex]) == 16)
|
|
|
|
|
$line .= " ";
|
|
|
|
|
|
|
|
|
|
if ($isl == 1) {
|
|
|
|
|
$line .= " " . $varname[$varNum];
|
2024-05-11 18:42:44 +03:00
|
|
|
|
} else {
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$line .= $varname[$varNum];
|
2024-05-11 18:42:44 +03:00
|
|
|
|
}
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$cur++;
|
2024-05-11 18:42:44 +03:00
|
|
|
|
} else { ///operator
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$isl = 0;
|
|
|
|
|
switch (hexdec($opType)) {
|
|
|
|
|
case 0x0e:
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$line .= " REM ";
|
|
|
|
|
$str = hexdec($lims[$cur]); /// len
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$cur++;
|
|
|
|
|
for ($i = 0; $i < $str; $i++) {
|
|
|
|
|
$line .= iconv("WINDOWS-1251", "UTF-8", chr(hexdec($lims[$cur])));
|
|
|
|
|
$cur++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0xfd:
|
|
|
|
|
$line .= "\"";
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$str = hexdec($lims[$cur]);
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$cur++;
|
|
|
|
|
for ($i = 0; $i < $str; $i++) {
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$line .= str_replace('"', '\"', iconv("WINDOWS-1251", "UTF-8", chr(hexdec($lims[$cur]))));
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$cur++;
|
|
|
|
|
}
|
|
|
|
|
$line .= "\"";
|
|
|
|
|
break;
|
|
|
|
|
case 0x30:
|
|
|
|
|
$line .= " DATA ";
|
2024-05-11 18:42:44 +03:00
|
|
|
|
$str = hexdec($lims[$cur]);
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$cur++;
|
|
|
|
|
for ($i = 0; $i < $str; $i++) {
|
|
|
|
|
$line .= iconv("WINDOWS-1251", "UTF-8", chr(hexdec($lims[$cur])));
|
|
|
|
|
$cur++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0xf6:
|
|
|
|
|
$line .= "=";
|
|
|
|
|
break;
|
|
|
|
|
case 0xf8:
|
|
|
|
|
$line .= hexdec($lims[$cur]);
|
|
|
|
|
$cur++;
|
|
|
|
|
break;
|
|
|
|
|
case 0xf7:
|
|
|
|
|
$line .= "(";
|
|
|
|
|
continue 2;
|
|
|
|
|
case 0xf9:
|
|
|
|
|
$line .= hexdec($lims[$cur]);
|
|
|
|
|
$cur++;
|
|
|
|
|
break;
|
|
|
|
|
case 0xfa:
|
|
|
|
|
$line .= (hexdec($lims[$cur]) * 256 + hexdec($lims[$cur + 1]));
|
|
|
|
|
$cur = $cur + 2;
|
|
|
|
|
break;
|
|
|
|
|
case 0xfb:
|
|
|
|
|
$line .= (hexdec($lims[$cur]) * 16777216 + hexdec($lims[$cur + 1]) * 65536 + hexdec($lims[$cur + 2]) * 256 + hexdec($lims[$cur + 3]));
|
|
|
|
|
$cur = $cur + 4;
|
|
|
|
|
break;
|
2024-05-11 18:42:44 +03:00
|
|
|
|
case 0xfe: //float
|
|
|
|
|
if ($version == 1) {
|
|
|
|
|
$exp = (int) $this->tosbyte(hexdec($lims[$cur + 3]));
|
|
|
|
|
$m = (hexdec($lims[$cur]) * 65536 + hexdec($lims[$cur + 1]) * 256 + hexdec($lims[$cur + 2])) / 500000;
|
|
|
|
|
$e = 1;
|
|
|
|
|
if ($exp > 0) {
|
|
|
|
|
$d = 1;
|
|
|
|
|
for ($i = 0; $i < $exp; $i++)
|
|
|
|
|
$d = $d * 10;
|
|
|
|
|
$e = $d;
|
|
|
|
|
}
|
|
|
|
|
if ($exp < 0) {
|
|
|
|
|
$d = 1;
|
|
|
|
|
for ($i = $exp; $i < 0; $i++)
|
|
|
|
|
$d = $d / 10;
|
|
|
|
|
$e = $d;
|
|
|
|
|
}
|
|
|
|
|
$line .= (float) ($m * $e);
|
|
|
|
|
$cur = $cur + 4;
|
|
|
|
|
} else {
|
|
|
|
|
$line .= $float[hexdec($lims[$cur])];
|
|
|
|
|
$cur++;
|
2024-05-11 17:47:33 +03:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$line .= $ops[hexdec($opType)];
|
|
|
|
|
if ($opType == 15 || ($ops[$opType] ?? '') == ' READ ') {
|
|
|
|
|
$isDIM = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->readByte($this->data);
|
|
|
|
|
$line .= "\r\n";
|
|
|
|
|
$main .= $line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->init();
|
|
|
|
|
return $main;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function obfuscation($name) {
|
2024-05-11 18:42:44 +03:00
|
|
|
|
switch ($this->readInt($this->data)) {
|
|
|
|
|
case '4d420001':
|
|
|
|
|
$version = 1;
|
|
|
|
|
break;
|
|
|
|
|
case '4d420191':
|
|
|
|
|
$version = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$version = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ($version == 0) {
|
2024-05-11 17:47:33 +03:00
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
$main = "";
|
2024-05-11 18:42:44 +03:00
|
|
|
|
if ($version == 1)
|
|
|
|
|
$main .= pack('H*', "4d420001"); //writeHex
|
|
|
|
|
else
|
|
|
|
|
$main .= pack('H*', "4d420191");
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$varnum = hexdec($this->readShort($this->data));
|
|
|
|
|
$main .= pack('n*', $varnum); //writeShort
|
|
|
|
|
for ($i = 0; $i < $varnum; $i++) { //пропуск переменных
|
|
|
|
|
$this->readUTF($this->data);
|
|
|
|
|
$main .= $this->writeUTF(" ");
|
|
|
|
|
$main .= pack('H*', $this->readByte($this->data));
|
|
|
|
|
}
|
2024-05-11 18:42:44 +03:00
|
|
|
|
|
|
|
|
|
if ($version == 2) { //пропуск float для MB191
|
|
|
|
|
$floatnum = hexdec($this->readShort($this->data));
|
|
|
|
|
$main .= pack('n*', $floatnum);
|
|
|
|
|
for ($i = 0; $i < $varnum; $i++) {
|
|
|
|
|
$main .= pack('H*', $this->readInt($this->data));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$leng = hexdec($this->readShort($this->data));
|
2024-05-11 18:42:44 +03:00
|
|
|
|
if ($version == 1)
|
|
|
|
|
$main .= pack('n*', $leng + 7);
|
|
|
|
|
else
|
|
|
|
|
$main .= pack('n*', $leng + 1);
|
2024-05-11 17:47:33 +03:00
|
|
|
|
|
|
|
|
|
for ($i = 0; $i < $leng; $i++) {
|
|
|
|
|
$main .= pack('H*', $this->readByte($this->data));
|
|
|
|
|
}
|
|
|
|
|
$main .= pack('H*', "FFFF");
|
|
|
|
|
file_put_contents($name, $main);
|
|
|
|
|
}
|
|
|
|
|
$this->init();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tosbyte($byte) {
|
|
|
|
|
if (0 <= $byte && $byte <= 63)
|
|
|
|
|
return (int) $byte;
|
|
|
|
|
if (64 <= $byte && $byte <= 191)
|
|
|
|
|
return (int) (-(128 - $byte));
|
|
|
|
|
if (192 <= $byte && $byte <= 255)
|
|
|
|
|
return (int) (-(256 - $byte));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readInt($text) {
|
|
|
|
|
$this->data = substr($text, 4, strlen($text));
|
|
|
|
|
return bin2hex(substr($text, 0, 4));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readShort($text) {
|
|
|
|
|
$this->data = substr($text, 2, strlen($text));
|
|
|
|
|
return bin2hex(substr($text, 0, 2));
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-11 18:42:44 +03:00
|
|
|
|
function readByte($text, $dec = true) {
|
2024-05-11 17:47:33 +03:00
|
|
|
|
$this->data = substr($text, 1, strlen($text));
|
2024-05-11 18:42:44 +03:00
|
|
|
|
if ($dec)
|
|
|
|
|
return bin2hex(substr($text, 0, 1));
|
|
|
|
|
else
|
|
|
|
|
return substr($text, 0, 1);
|
2024-05-11 17:47:33 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readUTF() {
|
|
|
|
|
$to = hexdec($this->readShort($this->data));
|
|
|
|
|
$bombom = "";
|
|
|
|
|
while ($to <> 0) {
|
|
|
|
|
$bombom .= iconv("WINDOWS-1251", "UTF-8", chr(hexdec($this->readByte($this->data))));
|
|
|
|
|
$to--;
|
|
|
|
|
}
|
|
|
|
|
return $bombom;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function writeUTF($text) {
|
|
|
|
|
$pack = pack('n*', mb_strlen($text));
|
|
|
|
|
$pack .= pack('a*', $text);
|
|
|
|
|
return $pack;
|
|
|
|
|
}
|
|
|
|
|
}
|