编辑于2016年4月12日 - 请参阅下面!(第一个答案后)
我刚刚尝试找到一种可以处理两种情况的解决方案:您提供的情况和Elias Van Ootegerm的这个示例。
当然,它应该像我在其中一个评论中提到的那样进行改进,但它适用于您的示例:
$source = file_get_contents("source.php");
preg_match_all('/\$[\$a-zA-Z0-9\[\'.*\'\]]*/', $source, $matches);
$matches = array_unique($matches[0]);
$replacements = array();
$obfuscated_source = $source;
foreach($matches as $varName)
{
do
{
$randomName = substr(md5(rand()), 0, 7);
$randomName = "a" . $randomName;
}
while(in_array("$" . $randomName, $replacements));
if(substr($varName, 0,8) == '$GLOBALS')
{
$delimiter = substr($varName, 9, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$GLOBALS[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,8) == '$_SERVER')
{
$delimiter = substr($varName, 9, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_SERVER[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,5) == '$_GET')
{
$delimiter = substr($varName, 6, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_GET[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,6) == '$_POST')
{
$delimiter = substr($varName, 7, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_POST[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,7) == '$_FILES')
{
$delimiter = substr($varName, 8, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_FILES[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,9) == '$_REQUEST')
{
$delimiter = substr($varName, 10, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_REQUEST[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,9) == '$_SESSION')
{
$delimiter = substr($varName, 10, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_SESSION[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,5) == '$_ENV')
{
$delimiter = substr($varName, 6, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_ENV[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 0,8) == '$_COOKIE')
{
$delimiter = substr($varName, 9, 1);
if($delimiter == '$') $delimiter = '';
$newName = '$_COOKIE[' .$delimiter . $randomName . $delimiter . ']';
}
else if(substr($varName, 1, 1) == '$')
{
$name = substr($varName, 2, strlen($varName)-2);
$pattern = '/(?=\$)\$' . $name . '.*;/';
preg_match_all($pattern, $source, $varDeclaration);
$varDeclaration = $varDeclaration[0][0];
preg_match('/\s*=\s*["\'](?:\\.|[^"\\]])*["\']/', $varDeclaration, $varContent);
$varContent = $varContent[0];
preg_match('/["\'](?:\\.|[^"\\]])*["\']/', $varContent, $varContentDetail);
$varContentDetail = substr($varContentDetail[0], 1, strlen($varContentDetail[0])-2);
$replacementDetail = str_replace($varContent, substr($replacements["$" . $varContentDetail], 1, strlen($replacements["$" . $varContentDetail])-1), $varContent);
$explode = explode($varContentDetail, $varContent);
$replacement = $explode[0] . $replacementDetail . $explode[1];
$obfuscated_source = str_replace($varContent, $replacement, $obfuscated_source);
}
else
{
$newName = '$' . $randomName;
}
$obfuscated_source = str_replace($varName, $newName, $obfuscated_source);
$replacements[$varName] = $newName;
}
foreach($replacements as $before => $after)
{
$name_before = str_replace("$", "", $before);
$name_after = str_replace("$", "", $after);
$obfuscated_source = str_replace($name_before, $name_after, $obfuscated_source);
}
$file = fopen("result.php", "w");
fwrite($file, $obfuscated_source);
fclose($file);
编辑:仍有一些情况需要一些努力。至少某些变量声明可能无法正确处理!
此外,第一个正则表达式并不完美,我的当前状态是:
'/\$\$?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/'
但这不能得到预定义变量的索引值...但我认为它有一些潜力。如果您像这里一样使用它,您将获得所有18个涉及的变量...下一步可以确定变量名后是否跟随 [..]。如果是这样,任何预定义变量和这种情况,如 $g = $GLOBALS;
,以及对这种 $g
的进一步使用都将被覆盖...
编辑 2016年4月12日
由于LSerni和原始问题以及一些解决方案的一些评论,我还编写了一个解析方案,您可以在下面找到它。它处理了一个扩展示例文件,这是我的目标。如果您发现其他挑战,请告诉我!
新解决方案:
$variable_names_before = array();
$variable_names_after = array();
$function_names_before = array();
$function_names_after = array();
$forbidden_variables = array(
'$GLOBALS',
'$_SERVER',
'$_GET',
'$_POST',
'$_FILES',
'$_COOKIE',
'$_SESSION',
'$_REQUEST',
'$_ENV',
);
$forbidden_functions = array(
'unlink'
);
$data = file_get_contents("example.php");
$lock = false;
$lock_quote = '';
for($i = 0; $i < strlen($data); $i++)
{
if(($data[$i] == "'" || $data[$i] == '"'))
{
if($lock_quote == '')
{
$lock_quote = $data[$i];
$lock = true;
}
else if($data[$i] == $lock_quote)
{
$lock_quote = '';
$lock = false;
}
}
if(!$lock && $data[$i] == '$')
{
$start = $i;
if($data[$i+1] == '$')
{
$start++;
$i++;
}
$end = 1;
while(ctype_alpha($data[$start+$end]) || is_numeric($data[$start+$end]) || $data[$start+$end] == "_")
{
$end++;
}
$variable_name = substr($data, $start, $end);
if($variable_name == '$')
{
continue;
}
if(in_array($variable_name, $forbidden_variables))
{
}
else
{
if(!in_array($variable_name, $variable_names_before))
{
$variable_names_before[] = $variable_name;
$new_variable_name = "";
do
{
$new_variable_name = random_str(rand(5, 20));
}
while(in_array($new_variable_name, $variable_names_after));
$variable_names_after[] = $new_variable_name;
}
}
}
if(!$lock && strtolower(substr($data, $i, 8)) == 'function' && (!ctype_alpha($data[$i-1]) && !is_numeric($data[$i-1])))
{
$end = strpos($data, '(', $i);
$function_name = rtrim(substr($data, ($i+9), $end-$i-9));
if(in_array($function_name, $forbidden_functions))
{
}
else
{
if(!in_array($function_name, $function_names_before))
{
$function_names_before[] = $function_name;
$new_function_name = "";
do
{
$new_function_name = random_str(rand(5, 20));
}
while(in_array($new_function_name, $function_names_after));
$function_names_after[] = $new_function_name;
}
}
}
}
$possible_pre_suffixes = array(
array(
"prefix" => "= '",
"suffix" => "'"
),
array(
"prefix" => '= "',
"suffix" => '"'
),
array(
"prefix" => "='",
"suffix" => "'"
),
array(
"prefix" => '="',
"suffix" => '"'
),
array(
"prefix" => 'rn "',
"suffix" => '"'
),
array(
"prefix" => "rn '",
"suffix" => "'"
)
);
for($i = 0; $i < count($variable_names_before); $i++)
{
$data = str_replace($variable_names_before[$i], '$' . $variable_names_after[$i], $data);
$name = substr($variable_names_before[$i], 1);
for($j = 0; $j < count($possible_pre_suffixes); $j++)
{
$data = str_replace($possible_pre_suffixes[$j]["prefix"] . $name . $possible_pre_suffixes[$j]["suffix"],
$possible_pre_suffixes[$j]["prefix"] . $variable_names_after[$i] . $possible_pre_suffixes[$j]["suffix"],
$data);
}
}
for($i = 0; $i < count($function_names_before); $i++)
{
$data = str_replace($function_names_before[$i], $function_names_after[$i], $data);
}
function random_str($length, $keyspace = 'abcdefghijklmnopqrstuvwxyz')
{
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i)
{
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
示例输入文件:
$example = 'some $string';
$test = '$abc 123' . $example . '$hello here I "$am"';
if(isset($_POST['something'])){
echo $_POST['something'];
}
function exampleFunction($variable2){
echo $variable2;
}
exampleFunction($example);
$variable3 = array('example','another');
foreach($variable3 as $key => $var3val){
echo $var3val."somestring";
}
$test = "example";
$$test = 'hello';
exampleFunction($example);
exampleFunction($$test);
function getNewName()
{
return "test";
}
exampleFunction(${getNewName()});
我的函数输出结果:
$fesvffyn = 'some $string';
$zimskk = '$abc 123' . $fesvffyn . '$hello here I "$am"';
if(isset($_POST['something'])){
echo $_POST['something'];
}
function kainbtqpybl($yxjvlvmyfskwqcevo){
echo $yxjvlvmyfskwqcevo;
}
kainbtqpybl($fesvffyn);
$lmiphctfgjfdnonjpia = array('example','another');
foreach($lmiphctfgjfdnonjpia as $qypdfcpcla => $gwlpcpnvnhbvbyflr){
echo $gwlpcpnvnhbvbyflr."somestring";
}
$zimskk = "fesvffyn";
$$zimskk = 'hello';
kainbtqpybl($fesvffyn);
kainbtqpybl($$zimskk);
function tauevjkk()
{
return "zimskk";
}
kainbtqpybl(${tauevjkk()});
我知道还有一些情况会出现变量变量名的问题,但这时你可能需要扩展$possible_pre_suffixes
数组...
也许您还想区分全局变量和“禁止使用的变量”...
'varname'
)为$varname
的新变量名。当然,$var1
的值可能是由函数返回的字符串($var1 = $this->getPropertyName(); return $this->{$var1};
),所以getPropertyName
必须返回随机字符串... 这就是事情变得非常棘手的地方。 - Elias Van Ootegem