盛大69棋牌游戏木马分析
本帖最后由 零度x 于 2014-1-16 11:42 编辑首先我们先来看一下这个游戏的加载方式,这个游戏是用ADOBE的AIR技术开发的
可以看到,游戏安装完成后核心是这3个文件,其中DeskPokerLoad.exe是主程序,运行后会调用游戏目录下的69game\AdobeAIR\Versions\1.0\Adobe AIR.dll,这个DLL会加载DeskPokerLoader.swf这个文件,这个文件会加载DeskPokerLoader.swf这个SWF文件,这个SWF只是个加载器,我们来看下反编译代码上面标记箭头那个就是加载完成的回调函数,我们跟进去看一下可以看到,这里运用了一个AS3的第三方库hurlant 里的DES算法去解密密钥是,官网在这里https://code.google.com/p/as3crypto/
这里解密完了的数据在_loc_2里面,我们可以自己写代码等它解密完后把它保存一下这里我们使用FLASHDEVELOP,当然这个软件只是个IDE,你要自己去下SDK和FLASHC CS 版本无所谓,一定要建AIR工程,不然不能使用文件保存功能,这里是是完整的代码package
{
import flash.display.Sprite;
import com.hurlant.crypto.symmetric.*;
import flash.events.*;
import flash.net.*;
import flash.utils.*;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
/**
*...
*@author 004
*/
public class Main extends Sprite
{
public static var swf_name:String ="DeskPoker.swf";
private var key:String ="activetuts";
private var urlload:URLLoader;
//=============================写入函数
public static function writeAppFile(fileName:String,datas:ByteArray):void{
var file:File = newFile(File.applicationDirectory.resolvePath(fileName).nativePath);
var fs:FileStream = new FileStream();
fs.open(file,FileMode.WRITE);
fs.position = 0;
fs.writeBytes(datas);
fs.close();
}
public function Main():void
{
this.urlload = new URLLoader();
this.urlload.dataFormat =URLLoaderDataFormat.BINARY;
this.urlload.addEventListener(Event.COMPLETE,this.loadLocalSWFComplete);
var _loc_1:* = newURLRequest(swf_name);
_loc_1.cacheResponse = false;
_loc_1.useCache = false;
this.urlload.load(_loc_1);
} //==========================加载完成回调 private functionloadLocalSWFComplete(event:Event) : void {
var _loc_2:* = this.urlload.data;
var _loc_3:* = new ByteArray();
_loc_3.writeUTF(this.key);
var _loc_4:* = new DESKey(_loc_3);
var _loc_5:* = _loc_2.length &~127;
var _loc_6:* = 0;
while (_loc_6 < _loc_5)
{
_loc_4.decrypt(_loc_2, _loc_6);
_loc_6 = _loc_6 + 128;
}
this.urlload.removeEventListener(Event.COMPLETE, this.loadLocalSWFComplete);
this.urlload.close();
writeAppFile("C:\\Decode.swf",_loc_2);
}
}
}//=======================================我们把DeskPoker.swf拷贝到和编译好的解码SWF下的BIN同一个目录,然后对这个函数下断点单步看看可以看到这里循环文件的大小进行相对解密,然后我们就直接把解密后的主SWF抠出来了//====================讲完解密后我们在来看看这个程序的登录方式和所有程序一样嘛,我们来找按钮事件可以看到舞台里有个这个和登录界面一样我们记住这个loginform然后在代码里去找然后我们对这个类名查找所有引用得到这个然后我们再对this.lf查找引用得到这句,这个是给按钮增加一个单击事件,我们来到onLogin这个函数我们略掉一些代码看核心的这里可以看到,取回用户名和密码还有验证码之后广播了一个login_tocom_enter消息,我们跟到消息处理函数可以看到这里调用HTTP发送了一个tc_ask_mibao,tc_ask_mibao定义为我们对程序抓包看一下,这是第一个包POST/G69LoginAPI/wechat/getlogintcard.jsp HTTP/1.1..Referer:app:/DeskPokerLoader.swf/[]/1..Accept: text/xml, application/xml,application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8, text/css, image/png,image/jpeg, image/gif;q=0.8, application/x-shockwave-flash, video/mp4;q=0.9,flv-application/octet-stream;q=0.8, video/x-flv;q=0.7, audio/mp4,application/futuresplash, */*;q=0.5..x-flash-version: 11,1,102,58..Content-Type:application/x-www-form-urlencoded..Content-Length: 19..Accept-Encoding:gzip,deflate..User-Agent: Mozilla/5.0 (Windows; U; zh-CN) AppleWebKit/533.19.4(KHTML, like Gecko) AdobeAIR/3.1..Host: login.game69.com:8080..Connection:Keep-Alive....param=sfz009910&t=0//============然后它的HTTP发送类注册了一个回调函数用来接收返回的包这里大概是根据返回包的xyh来进行操作比如这里返回的是{"res":1,"xyh":20006}查找下getMibaoRe这个消息这里res=1这个就是第二个包好了,类似于这样,节省篇幅,我们直接跳到密码那里可以看到发送密码的方式是这样,把密码机上jym这里是从服务器返回的一串数字,类似于这样"jym":"958184970",比如我密码是12345就是12345958184970,然后传给MD5进行加密后传到服务器,这里大概原理讲得差不多了,我们来看一下木马这里比原版多了一个DLL文件,可以看到,这里的2个SWF文件都成一样了,其实就是木马作者把原版SWF解密出来后把原来的加载SWF替换成主SWF了,这里木马盗取密码的方式是这样的,修改原版的SWF文件,在发送密码+JYM组成的MD5的时候改成这样了
右边那个是木马的修改版,可以看到直接返回了,我们再来看看那个DLL文件
可以看到它HOOK了3个函数,我们先来看看send函数,首先判断方法这里我们直接看登录页面这里就提取数组了,我们看看原版的包是怎样的POST/G69LoginAPI/login.jsp HTTP/1.1..Referer:app:/DeskPokerLoader.swf/[]/1..Accept: text/xml, application/xml,application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8, text/css, image/png,image/jpeg, image/gif;q=0.8, application/x-shockwave-flash, video/mp4;q=0.9,flv-application/octet-stream;q=0.8, video/x-flv;q=0.7, audio/mp4,application/futuresplash, */*;q=0.5..x-flash-version: 11,1,102,58..Content-Type:application/x-www-form-urlencoded..Content-Length: 114..Accept-Encoding:gzip,deflate..User-Agent: Mozilla/5.0 (Windows; U; zh-CN) AppleWebKit/533.19.4(KHTML, like Gecko) AdobeAIR/3.1..Host: login.game69.com:8080..Connection:Keep-Alive..Cookie:JSESSIONID=7349A2008A40E3D2D3E41AF5CED014E1....type=1&pw=ce5d8df64486b34bfa0bb75ca16c429f&yzm=%E8%AF%B7%E8%BE%93%E5%85%A5%E9%AA%8C%E8%AF%81%E7%A0%81&un=sfz009910但被木马修改版的就成这样了type=1&pw=12345958184970=%E8%AF%B7%E8%BE%93%E5%85%A5%E9%AA%8C%E8%AF%81%E7%A0%81&un=sfz009910//=========这里木马扣除密码后,再根据原版密码和那个JYM加密成MD5装到包里发送给服务器还会在本地保存一份然后就会给服务器发消息了,调用这个函数格式化是这样的这样吧,我们动态调试一下,首先对HOOK的SEND下个断点,再对格式化这个函数下个断点,可以看到这种,这里那个扫描8T1L的好像是计算机名密码和用户是出来了,再F9一下可以看到多了一串32位的MD5,这串MD5是怎么来的呢,是它自己生成的typedefstruct {
ULONG i;
ULONG buf;
unsigned char in;
unsigned char digest;
} MD5_CTX;
typedef void(CALLBACK* MD5Init_Tpye)(MD5_CTX* context);
typedef void(CALLBACK* MD5Update_Tpye)(MD5_CTX* context, unsigned char* input, unsigned int inlen);
typedef void(CALLBACK* MD5Final_Tpye)(MD5_CTX* context);
int main(intargc, char* argv[])
{
HINSTANCE hDLL =LoadLibrary("advapi32.dll");
MD5Init_Tpye MD5Init;
MD5Update_Tpye MD5Update;
MD5Final_TpyeMD5Final;
MD5Init =(MD5Init_Tpye)GetProcAddress(hDLL, "MD5Init");
MD5Update =(MD5Update_Tpye)GetProcAddress(hDLL, "MD5Update");
MD5Final =(MD5Final_Tpye)GetProcAddress(hDLL, "MD5Final");
MD5_CTX md5_context;
MD5Init(&md5_context);
unsigned char src;
unsigned length = strlen(argv);
memcpy(src, argv, length);
MD5Update(&md5_context, src, length);
MD5Final(&md5_context);
char dest = { 0 };
char *p = dest;
for(int i = 0; i < 16; ++i)
{
sprintf(p,"%02x",md5_context.digest);
p += 2;
}
cout << dest << endl;
return 0;
}//============用的是这个方法,那么生成这串MD5的是什么东西呢,这里第一次其实是空的没啥用,要知道是干嘛用的我们还要首先说一下,棋牌游戏都有个绑定机器的功能,我们让它进入游戏后,看一下有个绑定按钮,我们按一下可以看到马上就断下了可以看到这个MD5变了,这究竟是为什么呢?给我捐款我就告诉你 - -,抱怨一下,好了,我们想要知道为什么肯定就要去找源码来看看,期间步骤我就不说了,直接来到关键点,发送绑定消息后服务器会返回一个一个code什么什么,可以看到这里把返回的这个CODE保存了,看一下登录的时候有个这里的意思就是获取MAC加上什么东西然后加密成MD5发送,可是this.getmac()这个函数是个空函数,那么完全就依靠后来的readfile函数了,等于读取的就是之前服务器返回的那串,这下知道木马为什么截取这个MD5了吧,这里我们玩玩谢幕游戏,根据DLL里的什么OutputDebugStringA("yushaowoshimima");可以社工下,其实这些无聊可以不看了查下它服务器的IP然后我们扫描一下但我这个是内网,具体成功没我也不知道没去试了,好了这个样本我就不上传,以防被别人拿去用。 沙发 膜拜下楼主 好文章 简单的会点 难得不会 很详细的过程, 还只会 简单 的ODE 虽然很详细 但是功力不够看不懂 支持 原创描写得很详细,学习了! 很详细的教程,不写个专杀工具出来多可惜啊。。我也一直想知道分析木马是用什么软件载入分析的 谢谢分享 学习了,多谢分享 谢谢,虽然看不懂,还是膜拜先