某坏人游戏app

分析了十几款协议棋牌app协议,挑一个简单的记录一下

unsigned __int8 *__fastcall cocos2d::CCFileUtils::getFileData(cocos2d::CCFileUtils *this, const char *a2, const char *a3, unsigned int *a4)
...
///r4保存new出来的地址
.text:76BD1D64                 MOV     R0, R5          ; unsigned int
.text:76BD1D68                 BL      j__Znaj         ; operator new[](uint)
.text:76BD1D6C                 MOV     R4, R0

.text:76BD1D70                 MOV     R0, R4          ; ptr
.text:76BD1D74                 MOV     R1, #1          ; size
.text:76BD1D78                 MOV     R2, R5          ; n
.text:76BD1D7C                 MOV     R3, R7          ; stream

//fopen读取文件
.text:76BD1D80                 BL      fread
.text:76BD1D84                 STR     R0, [R6]
.text:76BD1D88                 MOV     R0, R7          ; stream
.text:76BD1D8C                 BL      fclose
.text:76BD1D90                 LDR     R0, [R6]
.text:76BD1D94                 CMP     R0, #8
.text:76BD1D98                 BCC     loc_76BD1E44
.text:76BD1D9C                 LDRB    R1, [R4]

//读取到的文件内容的头8个字节与 fuckyou! 依次比较
.text:76BD1DA0                 CMP     R1, #0x66 ; 'f'
.text:76BD1DA4                 LDREQB  R1, [R4,#1]
.text:76BD1DA8                 CMPEQ   R1, #0x75 ; 'u'
.text:76BD1DAC                 BNE     loc_76BD1E44
.text:76BD1DB0                 LDRB    R1, [R4,#2]
.text:76BD1DB4                 CMP     R1, #0x63 ; 'c'
.text:76BD1DB8                 LDREQB  R1, [R4,#3]
.text:76BD1DBC                 CMPEQ   R1, #0x6B ; 'k'
.text:76BD1DC0                 BNE     loc_76BD1E44
.text:76BD1DC4                 LDRB    R1, [R4,#4]
.text:76BD1DC8                 CMP     R1, #0x79 ; 'y'
.text:76BD1DCC                 LDREQB  R1, [R4,#5]
.text:76BD1DD0                 CMPEQ   R1, #0x6F ; 'o'
.text:76BD1DD4                 BNE     loc_76BD1E44
.text:76BD1DD8                 LDRB    R1, [R4,#6]
.text:76BD1DDC                 CMP     R1, #0x75 ; 'u'
.text:76BD1DE0                 LDREQB  R1, [R4,#7]
.text:76BD1DE4                 CMPEQ   R1, #0x21 ; '!'
.text:76BD1DE8                 BNE     loc_76BD1E44

//memmove8个字节,也就是跳过'fuckyou!'
.text:76BD1DEC                 SUB     R7, R0, #8
.text:76BD1DF0                 ADD     R1, R4, #8
.text:76BD1DF4                 MOV     R0, R4
.text:76BD1DF8                 MOV     R2, R7
.text:76BD1DFC                 STR     R7, [R6]
.text:76BD1E00                 BL      __aeabi_memmove

.text:76BD1E04                 CMP     R7, #0
.text:76BD1E08                 BEQ     loc_76BD1E44

//r1保存byte_76F8FD78地址, r0 = 0
.text:76BD1E0C                 LDR     R1, =(byte_76F8FD78 - 0x76BD1E1C)
.text:76BD1E10                 MOV     R0, #0
.text:76BD1E14                 ADD     R1, PC, R1      ; byte_76F8FD78
.text:76BD1E18

.text:76BD1E18                 MOV     R3, R0,ASR#31
.text:76BD1E1C                 LDRB    R2, [R4,R0]
.text:76BD1E20                 ADD     R3, R0, R3,LSR#24
.text:76BD1E24                 BIC     R3, R3, #0xFF
.text:76BD1E28                 SUB     R3, R0, R3
.text:76BD1E2C                 LDRB    R3, [R1,R3]

//内容异或
.text:76BD1E30                 EOR     R2, R2, R3
.text:76BD1E34                 STRB    R2, [R4,R0]

//每次递增r0
.text:76BD1E38                 ADD     R0, R0, #1
.text:76BD1E3C                 CMP     R0, R7


.text:76BD1E40                 BCC     loc_76BD1E18
.text:76BD1E44
.text:76BD1E44 loc_76BD1E44                            ; CODE XREF: cocos2d::CCFileUtils::getFileData(char const*,char const*,ulong *)+5C↑j
.text:76BD1E44                                         ; cocos2d::CCFileUtils::getFileData(char const*,char const*,ulong *)+C4↑j ...
.text:76BD1E44                 LDR     R1, =(off_770283F8 - 0x76BD1E54)
.text:76BD1E48                 LDR     R0, [SP,#0x28+filename]
.text:76BD1E4C                 LDR     R1, [PC,R1]     ; dword_77058630
.text:76BD1E50                 SUB     R6, R0, #0xC
.text:76BD1E54                 CMP     R6, R1
.text:76BD1E58                 BNE     loc_76BD1ED4
...
int LuaStack::luaLoadBuffer(lua_State *L, const char *chunk, int chunkSize, const char *chunkName)

...
.text:004CB0C4                 MOV     R0, #0
.text:004CB0C8                 SUB     R1, R6, R5      ; unsigned int
.text:004CB0CC                 STR     R0, [SP,#0x28+var_20]
.text:004CB0D0                 ADD     R0, SP, #0x28+var_20
.text:004CB0D4                 LDR     R2, [R4,#0x20]  ; unsigned __int8 *
.text:004CB0D8                 LDR     R3, [R4,#0x24]  ; unsigned int
.text:004CB0DC                 STR     R0, [SP,#0x28+var_28] ; unsigned int *
.text:004CB0E0                 ADD     R0, R7, R5      ; unsigned __int8 *

//调用_byds_d_解密
.text:004CB0E4                 BL      j__Z8_byds_d_PhjS_jPj ; _byds_d_(uchar *,uint,uchar *,uint,uint *)

.text:004CB0E8                 LDR     R4, [SP,#0x28+var_20]
.text:004CB0EC                 MOV     R5, R0
.text:004CB0F0                 MOV     R0, #0x100000
.text:004CB0F4                 STR     R0, [SP,#0x28+destLen]
.text:004CB0F8                 MOV     R0, #0x100000   ; unsigned int
.text:004CB0FC                 BL      j__Znaj         ; operator new[](uint)
.text:004CB100                 ADD     R1, SP, #0x28+destLen ; destLen
.text:004CB104                 MOV     R2, R5          ; source
.text:004CB108                 MOV     R3, R4          ; sourceLen
.text:004CB10C                 MOV     R6, R0

//调用uncompress解压
.text:004CB110                 BL      uncompress
...


//_byds_d_内部调用sub_76AC060C
.text:76AC060C sub_76AC060C  
...
//0xB54CDA56, 0x9E3779B9
.text:76AC072C                 BL      sub_76E97B68
.text:76AC0730                 LDR     R1, =0xB54CDA56
.text:76AC0734                 LDR     R3, =0x9E3779B9
.text:76AC0738                 LDR     R6, [SP,#0x30+ptr]
.text:76AC073C                 SUBS    R10, R4, #1
.text:76AC0740                 MLANE   LR, R0, R3, R1
.text:76AC0744                 CMPNE   LR, #0
.text:76AC0748                 BEQ     loc_76AC080C
.text:76AC074C                 LDR     R1, [SP,#0x30+var_28]
.text:76AC0750                 MOV     R0, R6

...

.rodata:76F74B00 byte_76F74B00   DCB 5, 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 9
.rodata:76F74B00                                         ; DATA XREF: HttpManagerLua::sendHttpRequest(HttpReqDefLua,char const*,char const*,uint)+484↑o
.rodata:76F74B00                                         ; .text:off_76862F94↑o ...
.rodata:76F74B00                 DCB 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 3, 0
.rodata:76F74B00                 DCB 0, 0, 0, 0, 0, 0


.text:768624C8 ; HttpManagerLua::sendHttpRequest(HttpReqDefLua, char const*, char const*, unsigned int)
...
.text:76862930 loc_76862930                            ; CODE XREF: HttpManagerLua::sendHttpRequest(HttpReqDefLua,char const*,char const*,uint)+454↑j
.text:76862930                 MOV     R0, R4          ; unsigned int
.text:76862934                 BL      j__Znaj         ; operator new[](uint)
.text:76862938                 MOV     R6, R0
.text:7686293C                 CMP     R7, #0
.text:76862940                 BEQ     loc_76862984
.text:76862944                 LDR     R1, =(byte_76F74B00 - 0x76862954)
.text:76862948                 MOV     R0, #0
.text:7686294C                 ADD     R1, PC, R1      ; byte_76F74B00
.text:76862950

// 除以10, 被编译成优化成乘法计算, 
.text:76862950                 LDR     R2, =0x66666667
.text:76862954                 SMULL   R3, R4, R0, R2
.text:76862958                 MOV     R2, R4,LSR#2
.text:7686295C                 LDRB    R3, [R5,R0]
.text:76862960                 ADD     R2, R2, R4,LSR#31
.text:76862964                 ADD     R2, R2, R2,LSL#2
.text:76862968                 SUB     R2, R0, R2,LSL#1
.text:7686296C                 LDR     R2, [R1,R2,LSL#2]

//异或
.text:76862970                 EOR     R2, R2, R3
.text:76862974                 STRB    R2, [R6,R0]
.text:76862978                 ADD     R0, R0, #1
.text:7686297C                 CMP     R7, R0
.text:76862980                 BNE     loc_76862950

以上汇编还原成python代码,大概就是

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import zlib
import struct
import xxtea

xor_key = [
    0xA4, 0x11, 0x98, 0xD3, 0xB2, 0x41, 0x27, 0x8F, 0x56, 0x14, 0xF1, 0x74, 0xF6, 0xCA, 0xE0, 0x7D,
    0x32, 0xFF, 0x92, 0xE2, 0x36, 0xA8, 0x94, 0x6E, 0xF0, 0x10, 0xDC, 0xF7, 0xC6, 0x66, 0x81, 0x91,
    0xE4, 0xA1, 0x12, 0x28, 0xF5, 0x3B, 0xAE, 0x1B, 0xD9, 0x6E, 0x64, 0x19, 0xC4, 0xD2, 0x19, 0x59,
    0x93, 0x23, 0x2D, 0xA1, 0x92, 0x54, 0xDD, 0xF2, 0xEF, 0x24, 0xD0, 0x9B, 0x3A, 0x20, 0xBE, 0x7C,
    0xF2, 0x6D, 0x3A, 0x66, 0x85, 0x77, 0x9B, 0x2B, 0x1A, 0xC8, 0xC6, 0x64, 0xFA, 0x62, 0xCB, 0xCA,
    0xAB, 0xC1, 0xC9, 0x21, 0x71, 0x96, 0xA3, 0xA9, 0xC7, 0xB0, 0x9A, 0xC2, 0x6B, 0x46, 0x9A, 0xBF,
    0xFC, 0x6C, 0xFA, 0x16, 0x5C, 0xEF, 0x90, 0xED, 0x9F, 0x6C, 0xAB, 0x25, 0x94, 0x5A, 0x5C, 0xAF,
    0x4E, 0x2A, 0xC4, 0xC6, 0xB0, 0xD8, 0x71, 0x50, 0x38, 0x82, 0x1A, 0xF7, 0x2A, 0x45, 0xE8, 0x2E,
    0x64, 0x9E, 0x65, 0x32, 0x7A, 0x3C, 0x33, 0x13, 0x51, 0x1F, 0xA7, 0x82, 0x67, 0x8D, 0xE9, 0x2C,
    0x4C, 0x7F, 0xA7, 0xCF, 0x9E, 0x2E, 0x79, 0x72, 0xB9, 0x72, 0xBF, 0x4F, 0x14, 0x53, 0x9B, 0xFC,
    0xD9, 0x3B, 0xEE, 0x15, 0xF8, 0xB0, 0x4C, 0xF1, 0xCB, 0x79, 0x9B, 0x5D, 0x42, 0xF7, 0xEB, 0xAE,
    0xEB, 0x8F, 0xB9, 0xBC, 0xBE, 0xA1, 0x7E, 0x9E, 0x38, 0xBE, 0xE9, 0x7D, 0xB2, 0x8D, 0x3D, 0x82,
    0x90, 0x39, 0xCD, 0x17, 0x49, 0xCF, 0x4B, 0xF2, 0x1C, 0x59, 0x2A, 0xA3, 0x73, 0x72, 0x66, 0xFE,
    0x3E, 0x30, 0xD5, 0xE4, 0xB9, 0x19, 0xD7, 0xAC, 0x72, 0x5F, 0x21, 0x37, 0x2E, 0x6B, 0x14, 0xA4,
    0x8C, 0x35, 0xC1, 0x16, 0xFF, 0xCC, 0xB3, 0x3F, 0x1D, 0x1A, 0xA4, 0xA5, 0xF1, 0x83, 0xD1, 0x99,
    0x29, 0x80, 0x25, 0xBD, 0xD0, 0x4E, 0xD8, 0x9C, 0xBE, 0xE9, 0xB8, 0xDD, 0xCB, 0x21, 0x94, 0x49
]

def lua_decrypt(path):
    with open(path, 'rb') as f:
        buf = f.read()[len('byds'):]
        zlib_buf = xxtea.decrypt(buf, '-4051-3138-1229-1250192182')
        ret = zlib.decompress(zlib_buf)
        return ret

def res_decrypt(path):
    out = []
    with open(path, 'rb') as f:
        buf = f.read()[len('fuckyou!'):]
        for index, i in enumerate(buf):
            out.append(chr(ord(i) ^ xor_key[index % len(xor_key)]))

        return ''.join(out)

def wanneng_xor(data):
    ret = []
    byte_76F74B00 = [5, 1, 6, 7, 9, 2, 4, 8, 3, 0]
    for index, i in enumerate(data):
        ret.append(chr(byte_7692FC10[index % len(byte_76F74B00)] ^ ord(i)))
    return ''.join(ret)


解密出lua和资源后,意外发现如果粗心的程序员打包了pb定义文件。
如果是标准protoc编译出来的cpp文件里面保存了二进制格式pb定义, 可以直接利用protoc的一些类库直接反向生成.proto文件

#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>

int main(int argc, char *argv[])
{
    google::protobuf::FileDescriptorProto fileProto;

    fileProto.ParseFromFileDescriptor(open(argv[1], O_RDONLY));
    google::protobuf::DescriptorPool pool;
    const google::protobuf::FileDescriptor* desc =
            pool.BuildFile(fileProto);
    std::cout << desc->DebugString() << std::endl;
    return 0;
}

有了pb,再分析出组包逻辑,签名算法。最后scrapy通过adsl代理做高频的协议巡检

posted @ 2019-05-23 14:03  tieyan  阅读(583)  评论(0编辑  收藏  举报