-
-
[原创]某传奇封包解密
-
2022-4-10 07:04
33299
-
一、前言
夜深人静.作为一名资深的导管选手.熟练的打开了www.xxx.com
一顿操作之后像往常一样准备关机睡觉.突然发现不知道什么时候桌面出现了一个xxx.apk的东西.于是乎怀着好奇的心放到模拟器准备瞧一瞧!
看到这个图标就感觉事情不简单. 好家伙!这不
是XD就来干我 大噶好 我系渣渣辉吗
由于最近异常无聊在研究封包这些东西.哼人家不找你你倒主动送上门了.讨厌
拿来吧你.
二、发包函数
总所周知.常见的发包函数有send.sendto.WSASend 以及重新实现的发包函数等.
通过发包函数可以定位到一些功能.比较常见的发包流程如下图:
但是现在的网游不会像多年前的网游一样,一个bp send 送你全套功能call以及明文发包,有的游戏你想找到真正的发包函数,都要消耗大量的精力.再或者当你跳出一个线程发包时你会发现你又来到了另外一个线程.
三、动态分析
通过观察发现不管是发送还是接收封包头部都会出现]TRA][nA]TRA]TRA]TRA]TRA]等字样.由此可以确定使用同一种加密.
那么想要查看封包的内容我们就必须解密或者找到明文包组包的位置.由于模拟器的限制并不能使用PC的工具.于是乎在网上搜索一番之后得到可以使用ceserver等工具.但是ceserver也有很多的bug.总是卡模拟器以及异常崩溃等等.
这里给大家推荐一个Android的Dbg.全名A64Dbg.可以在GitHub下载使用.
经过一系列尝试之后.发现A64Dbg里面没有游戏的主模块.这个本人也不熟悉Android.不知道是否被做了处理.
好吧.此路不通. 那就IDA大法.
四、静态分析
解压得到游戏.so文件拖入IDA.既然游戏需要发包.尝试是否可以搜到send相关的字符串.
我的天这么多太费事.苦力活咱不干.偶然发现.so的文件可以直接查看到function name.通过对send函数的交叉引用找到游戏发包位置伪代码.加密call以及BitMask.意外的发现还有DecodeBitMasks.
激动的心颤抖的手.气质挠一下就上来.抄就完了.
五、解密
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | std::vector< int > __fastcall Encode6BitBuf(std::vector< int > result, unsigned int a3, unsigned int * a4)
{
int v4; / / r8
int v5; / / r5
unsigned int v6; / / r12
unsigned int v7; / / r7
int v8; / / r6
bool v9; / / cc
char v10; / / r4
unsigned int v11; / / r5
std::vector< int > buffer ;
if (a3)
{
LOBYTE(v4) = 0 ;
v5 = 0 ;
v6 = 0 ;
int i = 0 ;
do
{
v7 = EncodeBitMasks[result[i]] ^ 9 ;
v8 = v5 + 2 ;
v9 = v5 + 2 < 6 ;
auto code = (((v7 >> (v5 + 2 )) | v4) & 0x3F ) + 0x3C ;
buffer .push_back(code);
v10 = 6 - v5;
v11 = v6 + 1 ;
v4 = (unsigned __int8)(v7 << v10) >> 2 ;
if (v9)
{
+ + v6;
v5 = v8;
}
else
{
v6 + = 2 ;
auto code2 = v4 + 0x3C ;
buffer .push_back(code2);
v5 = 0 ;
v4 = 0 ;
}
- - a3;
+ + i;
} while (a3);
if (v5 > 0 )
{
auto code3 = v4 + 0x3C ;
buffer .push_back(code3);
}
}
else
{
v6 = 0 ;
}
* a4 = v6;
return buffer ;
}
std::vector< int > __fastcall Decode6BitBuf(std::vector< int > result, unsigned int a3, unsigned int * a4)
{
int v4; / / r12
int v5; / / r4
int v6; / / r10
unsigned int v7; / / lr
int v8; / / r6
unsigned int v9; / / r5
unsigned __int8 v10; / / r5
std::vector< int > buffer ;
if (a3)
{
v4 = 0 ;
v5 = 2 ;
LOBYTE(v6) = 0 ;
v7 = 0 ;
v8 = 0 ;
while ( 1 )
{
v9 = result[v4];
if (v9 < 0x3C )
goto LABEL_12;
v10 = v9 - 0x3C ;
if (v8 > = 2 )
{
unsigned char code = DecodeBitMasks[(((unsigned __int8)(v10 & 0x3F ) >> ( 6 - v5)) | (unsigned __int8)v6) ^ 0x9E ] ^ 0x34 ;
buffer .push_back(code);
if (v5 > 5 )
{
v5 = 2 ;
v8 = 0 ;
goto LABEL_9;
}
v5 + = 2 ;
v8 = 0 ;
}
v6 = Decode6BitMask[v5 - 2 ] & (v10 << v5);
v8 = v8 + 8 - v5;
LABEL_9:
if ( + + v4 > = a3)
goto LABEL_12;
}
}
v7 = 0 ;
LABEL_12:
* a4 = v7;
return buffer ;
}
|
分析发现任务封包头部加密!其余封包全段加密!
通过对封包头部截取发现
列1.列3 可能为Type
列2.游戏重新打开时发生变化.那么我们是不是可以猜测是每次打开游戏与服务器做一些效验的字节.经过仔细分析打开登陆游戏时服务器向客户端发送的数据包认证了这一点
列4.每次点击发生变化.通过反复观察分析.确定列4为发包次数.最大为0xFF
六、总结
总体来说这一次的逆向没什么挑战.完全就是CV大法.游戏代码也应该是很久以前的老代码并没有做太多的修改以及防护.列如最近分析的一个PC游戏封包让我认识到了什么才叫兜圈子.也可能是本人封包经验欠缺.
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2023-10-24 17:16
被thisif编辑
,原因: 工具