278 lines
11 KiB
PHP
278 lines
11 KiB
PHP
<?php
|
|
session_start();
|
|
$version = '312E3031'; //1.01
|
|
ini_set("display_errors",0);
|
|
if(!empty($_FILES['file']['name']))
|
|
{
|
|
// echo $_FILES['file']['name'].'<br/>';
|
|
// require_once('functions.php');
|
|
|
|
//Get the g1a
|
|
$InFile = file_get_contents($_FILES['file']['tmp_name']);
|
|
$InFileSize = strlen($InFile);
|
|
$InFile = bin2hex($InFile);
|
|
//Check if the file is a g1a
|
|
if(strtolower($InFile[16].$InFile[17]) != '0c')
|
|
{
|
|
$_SESSION['msg_text']='The file is not recognized as a .g1a';
|
|
$_SESSION['msg_color']='red';
|
|
header("Location: ../");
|
|
exit;
|
|
}
|
|
//Check if the is not already edited by this tool
|
|
if(strtolower(substr($InFile,-60,52)) == '000053483420436f6d7061746962696c69747920546f6f6c2076')
|
|
{
|
|
$_SESSION['msg_text']='This file has already been modified by this tool. (version '.hex2bin(substr($InFile,-8)).')';
|
|
$_SESSION['msg_color']='red';
|
|
header("Location: ../");
|
|
exit;
|
|
}
|
|
//Verify if the file length is a divisible by 4 (cause the code that i add to the end is done only for this)
|
|
if($InFileSize%4 != 0)
|
|
{
|
|
$OutFile = str_pad($InFile, ($InFileSize+4-($InFileSize%4))*2, '0', STR_PAD_RIGHT);
|
|
$InFileSize = $InFileSize+4-($InFileSize%4);
|
|
}
|
|
else
|
|
$OutFile = $InFile;
|
|
//Input functions fix
|
|
$inputFix = false;
|
|
$GetKeyStateAdress = str_pad(dechex($InFileSize+0x300000), 8, '0', STR_PAD_LEFT);
|
|
//IsKeyDown
|
|
$isKeyDownCode = '4f227ffc63f3bee52f367f0463f0633c43118b0384f1600c401189037f044f26000be000bf5664f37f044f26000b0009';
|
|
$isKeyDownPosition = strpos($OutFile,$isKeyDownCode);
|
|
if($isKeyDownPosition !== false)
|
|
{
|
|
//Test if there is more than one function
|
|
if(strpos($OutFile,$isKeyDownCode,$isKeyDownPosition+1) !== false)
|
|
{
|
|
$_SESSION['msg_text']='Error : we found more than one IsKeyDown function !';
|
|
$_SESSION['msg_color']='red';
|
|
header("Location: ../");
|
|
exit;
|
|
}
|
|
//Replacement
|
|
$inputFix = true;
|
|
if(!isset($_POST['slow']))$slowcode = '00'; //fastmode
|
|
else $slowcode = '01'; //IsKeyDown Slowmode
|
|
$OutFile = substr($OutFile,0,$isKeyDownPosition+(0xc*2)) . '64F3E5'.$slowcode.'D003400B000900097F044F26000B0009' . $GetKeyStateAdress . substr($OutFile,$isKeyDownPosition+(0xc+20+4)*2);
|
|
}
|
|
// echo (strlen($OutFile)/2).'->0 <br/> ';
|
|
//IsKeyUp
|
|
$isKeyUpCode = '4f227ffc63f3becd2f367f0463f0633c43118b0384f1600c401189037f044f26000be000d208420b64f3200800297f044f26000b00095555a40001000000aaaa0000ff00a4000120';
|
|
$isKeyUpPosition = strpos($OutFile,$isKeyUpCode);
|
|
if($isKeyUpPosition !== false)
|
|
{
|
|
//Test if there is more than one function
|
|
if(strpos($OutFile,$isKeyUpCode,$isKeyUpPosition+1) !== false)
|
|
{
|
|
$_SESSION['msg_text']='Error : we found more than one IsKeyUp function !';
|
|
$_SESSION['msg_color']='red';
|
|
header("Location: ../");
|
|
exit;
|
|
}
|
|
//Replacement
|
|
$inputFix = true;
|
|
if(!isset($_POST['slow']))$slowcode = '00'; //fastmode
|
|
else $slowcode = '02'; //IsKeyUp Slowmode
|
|
$OutFile = substr($OutFile,0,$isKeyUpPosition+(0xc*2)) . '64F3E5'.$slowcode.'D004400B000900096007C9017F044F26000B0009' . $GetKeyStateAdress . substr($OutFile,$isKeyUpPosition+(0xc+24+4)*2);
|
|
}
|
|
// echo (strlen($OutFile)/2).'->1 <br/> ';
|
|
//KeyDown : pc%4=0
|
|
$keydownfix=false;
|
|
$KeyDownCode = '2fe6634c2fd6e50f2fc643092fb625492fa643092f96665c4f2260637ffc40112f308b01a005c90760077001c907600770016403';
|
|
$KeyDownPosition = strpos($OutFile,$KeyDownCode);
|
|
if($KeyDownPosition !== false)
|
|
{
|
|
//Test if there is more than one function
|
|
if(strpos($OutFile,$KeyDownCode,$KeyDownPosition+1) !== false)
|
|
{
|
|
$_SESSION['msg_text']='Error 1 : we found more than one KeyDown function !';
|
|
$_SESSION['msg_color']='red';
|
|
header("Location: ../");
|
|
exit;
|
|
}
|
|
$inputFix = true;
|
|
$keydownfix=true;
|
|
}
|
|
//KeyDown : pc%4=2
|
|
$KeyDown2Code = '634c2fe6e50f2fd643092fc625492fb643092fa6665c2f9660634f2240117ffc2f308b01a005c90760077001c90760077001';
|
|
$KeyDown2Position = strpos($OutFile,$KeyDown2Code);
|
|
if($KeyDown2Position !== false)
|
|
{
|
|
//Test if there is more than one function
|
|
if(strpos($OutFile,$KeyDown2Code,$KeyDown2Position+1) !== false || $keydownfix)
|
|
{
|
|
$_SESSION['msg_text']='Error 2 : we found more than one KeyDown function !';
|
|
$_SESSION['msg_color']='red';
|
|
header("Location: ../");
|
|
exit;
|
|
}
|
|
$inputFix = true;
|
|
$keydownfix=true;
|
|
//Decallage pour avoir pc%4=0
|
|
$OutFile = substr($OutFile,0,$KeyDown2Position) . '0009'. substr($OutFile,$KeyDown2Position+4);
|
|
$KeyDownPosition = $KeyDown2Position+4;
|
|
}
|
|
//KeyDown replacement
|
|
if($keydownfix)
|
|
{
|
|
if(!isset($_POST['slow']))$slowcode = '00'; //fastmode
|
|
else $slowcode = '03'; //IsKeyDown Slowmode
|
|
$OutFile = substr($OutFile,0,$KeyDownPosition) . '4F222F162F56E0FC6143410D6043C90F4118310C41282F1664F3E5'.$slowcode.'D004400B00097F0465F661F64F26000B00090009' . $GetKeyStateAdress . substr($OutFile,$KeyDownPosition+54+2+40+8);
|
|
}
|
|
//Part to add at the end for IsKeyDown, IsKeyUp, and KeyDown
|
|
if($inputFix)
|
|
{
|
|
$delayLoop = 'F6'; //-10
|
|
$OutFile .='4F222F162F262F362F662F762F862F96684369537FFC64F37FFC65F37FFC66F37FFC67F3D21F420BE0157F0866f07F0460f07F044018360C678084816803E0003087897BE1093817897830778976E106371789739023360389596083C907300CE603460D6083C907E501450D6557D00E401EE00830878B1960639111201AC101C50C910E2019CBAAC10CB065E4'.$delayLoop.'6053C022C438C9F0CB0FC038A01700090202AAAAFF0080010070A4000100902CC101C50C912A2019CBAA206AC10CB04CE4'.$delayLoop.'E0FFC022C438C9F0205BC038B044E4'.$delayLoop.'C4206607607B460DE0012609B03CE4'.$delayLoop.'9012C101C50C91102019CBAAC10CB033E4'.$delayLoop.'900BC101C50C91072019CB55C10CB02AE4'.$delayLoop.'A01B0009AAAAFF005555E00039078B007903D1086083C801318C890071FE6010E101417D201800296007C9016603A00400090000A44B0001E600B00B6493606369F668F667F666F663F662F661F64F26000B0009E00034038B14344CC702344C304C6102A00F0009'.
|
|
// Number of loop to emulate old functions
|
|
'00000001'. //fastest (can't be under 1)
|
|
'000006F7'. //IsKeyDown SH3
|
|
'00012D1F'. //IsKeyUp SH3
|
|
'00000001'. //KeyDown SH3
|
|
'000005CD'. //IsKeyDown SH4
|
|
'0000F1A8'. //IsKeyUp SH4
|
|
'00000001'. //KeyDown SH4
|
|
'614B41108BFD000B00090009';
|
|
}
|
|
//Syscall bug fix
|
|
$position = 0;
|
|
$SyscallFix = false;
|
|
$syscallCodeAddress = str_pad(dechex((strlen($OutFile)/2)+0x300000), 8, '0', STR_PAD_LEFT);
|
|
while(isset($OutFile[$position+3]))
|
|
{
|
|
if($OutFile[$position]=='4' && strtolower($OutFile[$position+1])=='f' && $OutFile[$position+2]=='2' &&$OutFile[$position+3]=='2')
|
|
{
|
|
//The instruction of the actual line is 4F22: sts.l pr,@-15
|
|
//The $position+4 or $position+8 instruction is d3xx:mov.l @(h'xx,pc),r3 // and @(h'xx,pc) contain the an address >= 0x08100000 (and we will suppose < 0x08200000)
|
|
$pc=0;
|
|
$valide = true;
|
|
if(strtolower($OutFile[$position+4]=='d') && $OutFile[$position+5]=='3')
|
|
{
|
|
$disp = ord(hex2bin($OutFile[$position+6].$OutFile[$position+7]));
|
|
$pc = ($position/2)+4;
|
|
$subOffset = 4;
|
|
}
|
|
elseif(strtolower($OutFile[$position+8]=='d') && $OutFile[$position+9]=='3')
|
|
{
|
|
$disp = ord(hex2bin($OutFile[$position+10].$OutFile[$position+11]));
|
|
$pc = ($position/2)+4+4;
|
|
$subOffset = 8;
|
|
}
|
|
else
|
|
$valide=false;
|
|
//Check if the address >= 0x08100000 and <0x08200000
|
|
if($valide)
|
|
{
|
|
$ToChange_Address = (($pc&0xFFFFFFFC)+($disp<<2))*2;
|
|
if(substr($OutFile,$ToChange_Address,3) != '081')
|
|
$valide=false;
|
|
}
|
|
//Search the row 92XX: mov.w @(h'xx,pc),r2 // This is the instruction that get the syscall number, so if I want it, I can. (just do as above)
|
|
if($valide)
|
|
{
|
|
$valide=false;
|
|
for($i=0;$i<=4;$i++)
|
|
{
|
|
if($OutFile[$position+$subOffset+($i*4)] == 'd' && $OutFile[$position+$subOffset+($i*4)+1] == '3')
|
|
{
|
|
$subOffset+=$i*4;
|
|
$valide = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//Search the row 6032: mov @R3,r0 // I need to edit this line to : mov r3,r0
|
|
if($valide)
|
|
{
|
|
$valide=false;
|
|
for($i=0;$i<=4;$i++)
|
|
{
|
|
if(substr($OutFile,$position+$subOffset+($i*4),4) == '6032')
|
|
{
|
|
$ToChange_Instruction = $position+$subOffset+($i*4);
|
|
$subOffset+=$i*4;
|
|
$valide = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//Search the row 400b: jsr @r0 //jump instruction
|
|
if($valide)
|
|
{
|
|
$valide=false;
|
|
for($i=0;$i<=4;$i++)
|
|
{
|
|
if(substr($OutFile,$position+$subOffset+($i*4),4) == '400b')
|
|
{
|
|
$subOffset+=$i*4;
|
|
$valide = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//Fixing
|
|
if($valide)
|
|
{
|
|
$SyscallFix = true;
|
|
//Change the mov instruction
|
|
$OutFile = substr($OutFile,0,$ToChange_Instruction) . '6033' . substr($OutFile,$ToChange_Instruction+4);
|
|
//Change the value moved (to the address of the code, to let him jump to it)
|
|
$OutFile = substr($OutFile,0,$ToChange_Address) . $syscallCodeAddress . substr($OutFile,$ToChange_Address+8);
|
|
}
|
|
}
|
|
$position+=4;
|
|
}
|
|
//Add the code for syscall if needed
|
|
if($SyscallFix)
|
|
{
|
|
$OutFile .= 'D201422B60F2000080010070';
|
|
}
|
|
//Add the version mark
|
|
$OutFile .= '0000000053483420436F6D7061746962696C69747920546F6F6C2076'.$version; //SH4 Compatibility Tool v$version
|
|
//Recalcul header
|
|
$OutFileSize = strlen($OutFile)/2;
|
|
if($InFileSize != $OutFileSize)
|
|
{
|
|
//OFFSET 0xE : last filesize byte + 65(0x41) and NOT (inverted)
|
|
$offset0xE = $OutFileSize + 0x41;
|
|
$offset0xE = 0xFFFFFFFF - $offset0xE;
|
|
$offset0xE = dechex($offset0xE);
|
|
$offset0xE = str_pad($offset0xE, 2, '0', STR_PAD_LEFT);
|
|
$offset0xE = substr($offset0xE, -2); // take the last byte
|
|
//OFFSET 0x10 : filesize NOT (inverted)
|
|
$offset0x10 = 0xFFFFFFFF - $OutFileSize;
|
|
$offset0x10 = dechex($offset0x10);// to hex
|
|
$offset0x10 = str_pad($offset0x10, 8, '0', STR_PAD_LEFT);
|
|
//OFFSET 0x14 : last filesize byte + 184(0xB8) and NOT (inverted)
|
|
$offset0x14 = $OutFileSize + 0xB8;
|
|
$offset0x14 = 0xFFFFFFFF - $offset0x14;
|
|
$offset0x14 = dechex($offset0x14);
|
|
$offset0x14 = str_pad($offset0x14, 2, '0', STR_PAD_LEFT);
|
|
$offset0x14 = substr($offset0x14, -2);
|
|
//OFFSET 0x1f0 : filesize
|
|
$offset0x1f0 = $OutFileSize;
|
|
$offset0x1f0 = dechex($offset0x1f0);// to hex
|
|
$offset0x1f0 = str_pad($offset0x1f0, 8, '0', STR_PAD_LEFT);
|
|
//Modifs
|
|
$OutFile = substr($OutFile,0,0xE*2). $offset0xE . substr($OutFile,0xf*2,2).
|
|
$offset0x10 . substr($OutFile,0x14*2,0x1dc*2) . $offset0x1f0 . substr($OutFile,0x1f4*2);
|
|
// echo $InFileSize . ' - ' .$OutFileSize;exit;
|
|
}
|
|
//making
|
|
$fileContent = pack('H*',$OutFile);
|
|
//sending
|
|
header('Content-Type: application/octet-stream');
|
|
header('Content-Disposition: attachment;filename="'.substr($_FILES['file']['name'],0,-4).'.g1a"');
|
|
header('Cache-Control: max-age=0');
|
|
$fh = fopen('php://output', 'wb');
|
|
fwrite($fh, $fileContent);
|
|
fclose($fh);
|
|
|
|
}
|
|
else
|
|
{
|
|
header("Location: ../");
|
|
}
|
|
?>
|