首页
社区
课程
招聘
[原创]2015年AliCrackMe第二题的分析之人肉过反调试
发表于: 2020-4-2 23:04 7556

[原创]2015年AliCrackMe第二题的分析之人肉过反调试

2020-4-2 23:04
7556

我是一个利用下班空余时间学习了一个月Android逆向的萌新,有多年的C/C++/Android开发经验,学习逆向的过程中,每当达成一个阶段的学习目标,都想找一个样本来试试手。这不,为了巩固一下前面学习的知识,找了很久找到这个样本,但是在百度上搜索的时候,我发现这个样本很出名,到处都有文章提到他的解法,我刻意避开了各位大佬的解法,下好样本,迅速关闭网页,然后自己动手开搞。
注:本帖中使用到的工具的基本使用方法我就不过多的讲述了,直接说思路,可能大佬只需要简单的一个调试或者Hook,马上就会知道答案,但是,原谅我,我是新人,我暂时只能用最基础的方法来解,没有抄袭,绝对原创,希望对新手起到启发作用,相互交流,有不正确的地方,大佬们还请斧正。
先安装APP看看是个什么妖魔鬼怪,如下图:

很有意境,左下角有一个看雪的logo,阿里和看雪联合出品,我立马意识到,这件事并没有那么简单。
接下来先进行一波静态分析,直接把Apk拖入到jadx中,如下图:

代码没有混淆,很清晰的逻辑,点击“输入密码”按钮之后,直接调用native接口securityCheck,加载的是libcrackme.so这个库,看来密码校验是在native里面了,那就只有请出我们的神器IDA了。
代码没有混淆,很清晰的逻辑,点击“输入密码”按钮之后,直接调用native接口securityCheck,加载的是libcrackme.so这个库,看来密码校验是在native里面了,那就只有请出我们的神器IDA了。
先用Apktool反编译APK,用IDA打开APK反编译出来的目录下的lib/armeabi/libcrackme.so,发现native接口没有在JNI_OnLoad函数里面注册,直接用“Java_包名_function”的方式定义,这就是告诉你,点这个函数就行了,那就点开这个函数,如下图:

浏览了一遍汇编代码,发现大致能看懂,但是不直观,那就F5直接反汇编,看C语言伪代码,如下图:

参数a1的类型应该是JNIEnv*,它被赋值给了v3,(*(_DWORD)v3+676)又作为了一个函数指针被调用,那么应该很快想到JNIEnv这个结构体,里面存放的是它所在JavaVM所包含的所有函数指针;参数a3是jstring类型,被付给了v4,v4又是作为(*(_DWORD)v3+676)函数的第二个变量,大致隐约能感觉到这个函数是在转换字符串,我们选中a1和a3变量,点击“Y”,修改a1的类型为JNIEnv*,修改a3类型为jstring,修改之后的函数就一目了然了,如下图:
v5是a3变量通过JNIEnv.GetStringUTFChars这个函数转成一个C型的字符串,再和v6做比较,那么v6不出意外就是密码了,我们双击off_628C这个变量,如下图:

WWWhat? “wojiushidaan”? 这就是密码,这么简单,心里一阵狂喜,直接把“wojiushidaan”输入到输入框,点击“输入密码”,一个让人沮丧的Toast弹出了,“验证码校验失败”,看来,这玩意儿果真没有想象中那么简单,那就只有动态调试了,巴拉巴拉一阵IDA动态调试基础操作之后,每次Attach到进程之后,进程马上就闪退,可能有反调试,那就继续静态分析啊,看哪里在做反调试的操作,本能式的先找到JNI_OnLoad函数,函数反汇编如下:
signed int __fastcall JNI_OnLoad(int a1)
{
  int v1; // r4
  _DWORD *v2; // r5
  int v3; // r6
  _DWORD *v4; // r6
  signed int v5; // r6
  int v7; // [sp-8h] [bp-28h]
  char v8; // [sp+0h] [bp-20h]

  v1 = a1;
  dword_62C8 = 0;
  v2 = (_DWORD *)dword_62C4;
  if ( dword_62C4 )
  {
    do
    {
      if ( *v2 >= 1 )
      {
        v3 = 0;
        do
          ((void (*)(void))v2[v3++ + 1])();
        while ( v3 < *v2 );
      }
      v4 = (_DWORD *)v2[11];
      free(v2);
      v2 = v4;
    }
    while ( v4 );
    dword_62C4 = 0;
  }
  dword_62B4(&v8, 0, sub_16A4, 0, 0);
  sub_17F4();
  v5 = 65540;
  if ( (*(int (__fastcall **)(int, int *, signed int))(*(_DWORD *)v1 + 24))(v1, &v7, 65540) )
    v5 = -1;
  return v5;
}
通篇看了代码,没有一个见过的函数名,逐层浏览函数调用之后发现很多的函数调用都是一些普通int型变量在作为函数指针调用,似乎有点像函数指针的调用方法,那这些函数指针都是哪里赋值的呢?思考2秒之后,反应过来,.init_array段。
signed int __fastcall JNI_OnLoad(int a1)
{
  int v1; // r4
  _DWORD *v2; // r5
  int v3; // r6
  _DWORD *v4; // r6
  signed int v5; // r6
  int v7; // [sp-8h] [bp-28h]
  char v8; // [sp+0h] [bp-20h]

  v1 = a1;
  dword_62C8 = 0;
  v2 = (_DWORD *)dword_62C4;
  if ( dword_62C4 )
  {
    do
    {
      if ( *v2 >= 1 )
      {
        v3 = 0;
        do
          ((void (*)(void))v2[v3++ + 1])();
        while ( v3 < *v2 );
      }
      v4 = (_DWORD *)v2[11];
      free(v2);
      v2 = v4;
    }
    while ( v4 );
    dword_62C4 = 0;
  }
  dword_62B4(&v8, 0, sub_16A4, 0, 0);
  sub_17F4();
  v5 = 65540;
  if ( (*(int (__fastcall **)(int, int *, signed int))(*(_DWORD *)v1 + 24))(v1, &v7, 65540) )
    v5 = -1;
  return v5;
}
通篇看了代码,没有一个见过的函数名,逐层浏览函数调用之后发现很多的函数调用都是一些普通int型变量在作为函数指针调用,似乎有点像函数指针的调用方法,那这些函数指针都是哪里赋值的呢?思考2秒之后,反应过来,.init_array段。
直接IDA+Ctrl+S找到so的.init_array段,点击进入,发现一个sub_2378的代码段,如下图:

点击进入,F5反汇编之后发现是如下的调用关系:
int sub_2378()
{
  return sub_22AC((int)sub_1CA8);
}
sub_1CA8先调用那就先看sub_1CA8代码:
int sub_2378()
{
  return sub_22AC((int)sub_1CA8);
}
sub_1CA8先调用那就先看sub_1CA8代码:
int sub_1CA8()
{
  int (__fastcall *v0)(signed int, void *); // r4
  int result; // r0

  if ( !byte_635F )
  {
    sub_24F4(&unk_62D7, 6, &unk_4509, "9HbB", 4, 197);
    byte_635F = 1;
  }
  v0 = (int (__fastcall *)(signed int, void *))dlsym((void *)0xFFFFFFFF, (const char *)&unk_62D7);
  if ( !byte_6360 )
  {
    sub_24F4(&unk_62EF, 7, &unk_448B, &unk_4488, 2, 213);
    byte_6360 = 1;
  }
  dword_6294 = v0(-1, &unk_62EF);
  if ( !byte_6361 )
  {
    sub_239C(&unk_630C, 8, (char *)&unk_44F3, (int)"LNAt", 4u);
    byte_6361 = 1;
  }
  dword_6298 = v0(-1, &unk_630C);
  if ( !byte_6362 )
  {
    sub_239C(&unk_62DD, 6, (char *)&unk_44AC, (int)"cOXt", 4u);
    byte_6362 = 1;
  }
  dword_629C = v0(-1, &unk_62DD);
  if ( !byte_6363 )
  {
    sub_24F4(&unk_62E3, 6, &unk_4481, "BMT", 3, 1);
    byte_6363 = 1;
  }
  dword_62A0 = v0(-1, &unk_62E3);
  if ( !byte_6364 )
  {
    sub_239C(&unk_62F6, 7, (char *)&unk_44C4, (int)&unk_44C1, 2u);
    byte_6364 = 1;
  }
  dword_62A4 = v0(-1, &unk_62F6);
  if ( !byte_6365 )
  {
    sub_254C(&unk_62FD, 7, &unk_44CC, &unk_44FC, 0, 1);
    byte_6365 = 1;
  }
  dword_62A8 = v0(-1, &unk_62FD);
  if ( !byte_6366 )
  {
    sub_254C(&unk_62CC, 5, &unk_44A1, &unk_44FC, 0, 1);
    byte_6366 = 1;
  }
  dword_62AC = v0(-1, &unk_62CC);
  if ( !byte_6367 )
  {
    sub_254C(&unk_62E9, 6, &unk_44FD, &unk_44FC, 0, 1);
    byte_6367 = 1;
  }
  dword_62B0 = v0(-1, &unk_62E9);
  if ( !byte_6368 )
  {
    sub_258C(&unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4, 1);
    byte_6368 = 1;
  }
  dword_62B4 = v0(-1, &unk_633A);
  if ( !byte_6369 )
  {
    sub_258C(&unk_631C, 9, &unk_44E4, &unk_44E0, 3, 201);
    byte_6369 = 1;
  }
  dword_62B8 = v0(-1, &unk_631C);
  if ( !byte_636A )
  {
    sub_254C(&unk_632F, 11, &unk_44D4, &unk_44FC, 0, 1);
    byte_636A = 1;
  }
  dword_62BC = v0(-1, &unk_632F);
  if ( !byte_636B )
  {
    sub_258C(&unk_6314, 8, &unk_44B8, ".6gq", 4, 187);
    byte_636B = 1;
  }
  result = v0(-1, &unk_6314);
  dword_62C0 = result;
  return result;
}
初看这个函数很懵逼,但是看到dlsym函数之后,便豁然开朗,这就是通过dlsym获取动态库的函数指针,将所有用到的函数都用函数指针保存起来,隐藏函数本身的样式,加大过反调试的难度。
注:这里有个知识点,dlsym函数第一个参数handle可以带dlopen库的返回值,也可以带0xFFFFFFFF,带0xFFFFFFFF表示从当前内存加载的所有so中查找某个symbol
int sub_1CA8()
{
  int (__fastcall *v0)(signed int, void *); // r4
  int result; // r0

  if ( !byte_635F )
  {
    sub_24F4(&unk_62D7, 6, &unk_4509, "9HbB", 4, 197);
    byte_635F = 1;
  }
  v0 = (int (__fastcall *)(signed int, void *))dlsym((void *)0xFFFFFFFF, (const char *)&unk_62D7);
  if ( !byte_6360 )
  {
    sub_24F4(&unk_62EF, 7, &unk_448B, &unk_4488, 2, 213);
    byte_6360 = 1;
  }
  dword_6294 = v0(-1, &unk_62EF);
  if ( !byte_6361 )
  {
    sub_239C(&unk_630C, 8, (char *)&unk_44F3, (int)"LNAt", 4u);
    byte_6361 = 1;
  }
  dword_6298 = v0(-1, &unk_630C);
  if ( !byte_6362 )
  {
    sub_239C(&unk_62DD, 6, (char *)&unk_44AC, (int)"cOXt", 4u);
    byte_6362 = 1;
  }
  dword_629C = v0(-1, &unk_62DD);
  if ( !byte_6363 )
  {
    sub_24F4(&unk_62E3, 6, &unk_4481, "BMT", 3, 1);
    byte_6363 = 1;
  }
  dword_62A0 = v0(-1, &unk_62E3);
  if ( !byte_6364 )
  {
    sub_239C(&unk_62F6, 7, (char *)&unk_44C4, (int)&unk_44C1, 2u);
    byte_6364 = 1;
  }
  dword_62A4 = v0(-1, &unk_62F6);
  if ( !byte_6365 )
  {
    sub_254C(&unk_62FD, 7, &unk_44CC, &unk_44FC, 0, 1);
    byte_6365 = 1;
  }
  dword_62A8 = v0(-1, &unk_62FD);
  if ( !byte_6366 )
  {
    sub_254C(&unk_62CC, 5, &unk_44A1, &unk_44FC, 0, 1);
    byte_6366 = 1;
  }
  dword_62AC = v0(-1, &unk_62CC);
  if ( !byte_6367 )
  {
    sub_254C(&unk_62E9, 6, &unk_44FD, &unk_44FC, 0, 1);
    byte_6367 = 1;
  }
  dword_62B0 = v0(-1, &unk_62E9);
  if ( !byte_6368 )
  {
    sub_258C(&unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4, 1);
    byte_6368 = 1;
  }
  dword_62B4 = v0(-1, &unk_633A);
  if ( !byte_6369 )
  {
    sub_258C(&unk_631C, 9, &unk_44E4, &unk_44E0, 3, 201);
    byte_6369 = 1;
  }
  dword_62B8 = v0(-1, &unk_631C);
  if ( !byte_636A )
  {
    sub_254C(&unk_632F, 11, &unk_44D4, &unk_44FC, 0, 1);
    byte_636A = 1;
  }
  dword_62BC = v0(-1, &unk_632F);
  if ( !byte_636B )
  {
    sub_258C(&unk_6314, 8, &unk_44B8, ".6gq", 4, 187);
    byte_636B = 1;
  }
  result = v0(-1, &unk_6314);
  dword_62C0 = result;
  return result;
}
初看这个函数很懵逼,但是看到dlsym函数之后,便豁然开朗,这就是通过dlsym获取动态库的函数指针,将所有用到的函数都用函数指针保存起来,隐藏函数本身的样式,加大过反调试的难度。
注:这里有个知识点,dlsym函数第一个参数handle可以带dlopen库的返回值,也可以带0xFFFFFFFF,带0xFFFFFFFF表示从当前内存加载的所有so中查找某个symbol
既然知道了这个套路,那就得开始人肉解密了,因为现在还不知道具体调用了哪些C库的函数,也还不知道具体是怎么做的反调试,必须明确知道各个函数调用之后才能更清晰的看清楚程序的逻辑。分析了程序之后我们知道整个函数内各个函数指针的获取都调用了v0这个函数,那我们隐约感觉到v0可能就是dlsym的函数指针,验证一下,直接把解密函数的伪代码粘贴到任何一个你喜欢的C/C++ IDE里面,稍微修改一下参数的类型,代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
  char* v6; // r7
  unsigned int v7; // r4

  v6 = result;
  if ( a2 )
  {
    v7 = 0;
    do
    {
      result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
      *(char* *)(v6 + v7++) = result;
    }
    while ( a2 != v7 );
  }
  return result;
}

int main()
{
    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("unk_62D7:%s\n",(char*)unk_62D7);
    return 0;
}
代码运行结果如下:

unk_62D7:dlsym
果然不出所料啊,v0就是dlsym函数的指针,添加所有的解密函数,做一个解密小程序代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if defined(__GNUC__)
typedef          long long ll;
typedef unsigned long long ull;
#define __int64 long long
#define __int32 int
#define __int16 short
#define __int8  char
#define MAKELL(num) num ## LL
#define FMT_64 "ll"
#elif defined(_MSC_VER)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "I64"
#elif defined (__BORLANDC__)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "L"
#else
#error "unknown compiler"
#endif
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;

typedef          char   int8;
typedef   signed char   sint8;
typedef unsigned char   uint8;
typedef          short  int16;
typedef   signed short  sint16;
typedef unsigned short  uint16;
typedef          int    int32;
typedef   signed int    sint32;
typedef unsigned int    uint32;
typedef ll              int64;
typedef ll              sint64;
typedef ull             uint64;

// Partially defined types:
#define _BYTE  uint8
#define _WORD  uint16
#define _DWORD uint32
#define _QWORD uint64
#if !defined(_MSC_VER)
#define _LONGLONG __int128
#endif

#ifndef _WINDOWS_
typedef int8 BYTE;
typedef int16 WORD;
typedef int32 DWORD;
typedef int32 LONG;
#endif
typedef int64 QWORD;
#ifndef __cplusplus
typedef int bool;       // we want to use bool in our C programs
#endif

// Some convenience macros to make partial accesses nicer
// first unsigned macros:
#define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
#define LOWORD(x)   (*((_WORD*)&(x)))   // low word
#define LODWORD(x)  (*((_DWORD*)&(x)))  // low dword
#define HIBYTE(x)   (*((_BYTE*)&(x)+1))
#define HIWORD(x)   (*((_WORD*)&(x)+1))
#define HIDWORD(x)  (*((_DWORD*)&(x)+1))
#define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
#define WORDn(x, n)   (*((_WORD*)&(x)+n))
#define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
#define BYTE2(x)   BYTEn(x,  2)
#define BYTE3(x)   BYTEn(x,  3)
#define BYTE4(x)   BYTEn(x,  4)
#define BYTE5(x)   BYTEn(x,  5)
#define BYTE6(x)   BYTEn(x,  6)
#define BYTE7(x)   BYTEn(x,  7)
#define BYTE8(x)   BYTEn(x,  8)
#define BYTE9(x)   BYTEn(x,  9)
#define BYTE10(x)  BYTEn(x, 10)
#define BYTE11(x)  BYTEn(x, 11)
#define BYTE12(x)  BYTEn(x, 12)
#define BYTE13(x)  BYTEn(x, 13)
#define BYTE14(x)  BYTEn(x, 14)
#define BYTE15(x)  BYTEn(x, 15)
#define WORD1(x)   WORDn(x,  1)
#define WORD2(x)   WORDn(x,  2)         // third word of the object, unsigned
#define WORD3(x)   WORDn(x,  3)
#define WORD4(x)   WORDn(x,  4)
#define WORD5(x)   WORDn(x,  5)
#define WORD6(x)   WORDn(x,  6)
#define WORD7(x)   WORDn(x,  7)

// now signed macros (the same but with sign extension)
#define SLOBYTE(x)   (*((int8*)&(x)))
#define SLOWORD(x)   (*((int16*)&(x)))
#define SLODWORD(x)  (*((int32*)&(x)))
#define SHIBYTE(x)   (*((int8*)&(x)+1))
#define SHIWORD(x)   (*((int16*)&(x)+1))
#define SHIDWORD(x)  (*((int32*)&(x)+1))
#define SBYTEn(x, n)   (*((int8*)&(x)+n))
#define SWORDn(x, n)   (*((int16*)&(x)+n))
#define SBYTE1(x)   SBYTEn(x,  1)
#define SBYTE2(x)   SBYTEn(x,  2)
#define SBYTE3(x)   SBYTEn(x,  3)
#define SBYTE4(x)   SBYTEn(x,  4)
#define SBYTE5(x)   SBYTEn(x,  5)
#define SBYTE6(x)   SBYTEn(x,  6)
#define SBYTE7(x)   SBYTEn(x,  7)
#define SBYTE8(x)   SBYTEn(x,  8)
#define SBYTE9(x)   SBYTEn(x,  9)
#define SBYTE10(x)  SBYTEn(x, 10)
#define SBYTE11(x)  SBYTEn(x, 11)
#define SBYTE12(x)  SBYTEn(x, 12)
#define SBYTE13(x)  SBYTEn(x, 13)
#define SBYTE14(x)  SBYTEn(x, 14)
#define SBYTE15(x)  SBYTEn(x, 15)
#define SWORD1(x)   SWORDn(x,  1)
#define SWORD2(x)   SWORDn(x,  2)
#define SWORD3(x)   SWORDn(x,  3)
#define SWORD4(x)   SWORDn(x,  4)
#define SWORD5(x)   SWORDn(x,  5)
#define SWORD6(x)   SWORDn(x,  6)
#define SWORD7(x)   SWORDn(x,  7)


// Helper functions to represent some assembly instructions.

#ifdef __cplusplus

// Fill memory block with an integer value
inline void memset32(void *ptr, uint32 value, int count)
{
    uint32 *p = (uint32 *)ptr;
    for ( int i=0; i < count; i++ )
        *p++ = value;
}

// Generate a reference to pair of operands
template<class T>  int16 __PAIR__( int8  high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); }
template<class T>  int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); }
template<class T>  int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); }
template<class T> uint16 __PAIR__(uint8  high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); }
template<class T> uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); }
template<class T> uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); }

// rotate left
template<class T> T __ROL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T high = value >> (nbits - count);
    value <<= count;
    value |= high;
    return value;
}

// rotate right
template<class T> T __ROR__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T low = value << (nbits - count);
    value >>= count;
    value |= low;
    return value;
}

// carry flag of left shift
template<class T> int8 __MKCSHL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    return (value >> (nbits-count)) & 1;
}

// carry flag of right shift
template<class T> int8 __MKCSHR__(T value, uint count)
{
    return (value >> (count-1)) & 1;
}

// sign flag
template<class T> int8 __SETS__(T x)
{
    if ( sizeof(T) == 1 )
        return int8(x) < 0;
    if ( sizeof(T) == 2 )
        return int16(x) < 0;
    if ( sizeof(T) == 4 )
        return int32(x) < 0;
    return int64(x) < 0;
}

// overflow flag of subtraction (x-y)
template<class T, class U> int8 __OFSUB__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
    }
}

// overflow flag of addition (x+y)
template<class T, class U> int8 __OFADD__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
    }
}

// carry flag of subtraction (x-y)
template<class T, class U> int8 __CFSUB__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) < uint8(y);
    if ( size == 2 )
        return uint16(x) < uint16(y);
    if ( size == 4 )
        return uint32(x) < uint32(y);
    return uint64(x) < uint64(y);
}

// carry flag of addition (x+y)
template<class T, class U> int8 __CFADD__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) > uint8(x+y);
    if ( size == 2 )
        return uint16(x) > uint16(x+y);
    if ( size == 4 )
        return uint32(x) > uint32(x+y);
    return uint64(x) > uint64(x+y);
}

#else
// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((uint64)(high)<<sizeof(high)*8) | low)
// For C, we just provide macros, they are not quite correct.
#define __ROL__(x, y) __rotl__(x, y)      // Rotate left
#define __ROR__(x, y) __rotr__(x, y)      // Rotate right
#define __CFSHL__(x, y) invalid_operation // Generate carry flag for (x<<y)
#define __CFSHR__(x, y) invalid_operation // Generate carry flag for (x>>y)
#define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y)
#define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y)
#define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y)
#define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y)
#endif

// No definition for rcl/rcr because the carry flag is unknown
#define __RCL__(x, y)    invalid_operation // Rotate left thru carry
#define __RCR__(x, y)    invalid_operation // Rotate right thru carry
#define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL
#define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR
#define __SETP__(x, y)   invalid_operation // Generate parity flag for (x-y)

// In the decompilation listing there are some objects declarared as _UNKNOWN
// because we could not determine their types. Since the C compiler does not
// accept void item declarations, we replace them by anything of our choice,
// for example a char:

#define _UNKNOWN char

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

int __fastcall sub_239C(_BYTE *a1, int a2, char *a3, int a4, unsigned int a5)
{
  _BYTE *v5; // r11
  char *v6; // r10
  int v7; // r5
  int v8; // r0
  unsigned int v9; // r7
  char v10; // r6
  int v11; // r8
  int result; // r0
  int v13; // r1
  char v14; // r1
  int v15; // r1
  int v16; // r0
  char v17; // r2
  char v18; // t1
  char v19[256]; // [sp+8h] [bp-128h]
  __int16 v20; // [sp+108h] [bp-28h]

  v5 = a1;
  v6 = a3;
  v7 = a2;
  v8 = 0;
  do
  {
    v19[v8] = v8;
    ++v8;
  }
  while ( v8 != 256 );
  v9 = 0;
  v10 = 0;
  v20 = 0;
  do
  {
    v11 = (unsigned __int8)v19[v9];
    result = *(unsigned __int8 *)(a4 + v9 % a5) + v11;
    v13 = (unsigned __int8)(result + v10);
    v19[v9] = v19[v13];
    v19[v13] = v11;
    ++v9;
    v10 += result;
  }
  while ( v9 != 256 );
  if ( v7 )
  {
    LOBYTE(result) = HIBYTE(v20);
    v14 = v20;
    do
    {
      LOBYTE(v15) = v14 + 1;
      --v7;
      LOBYTE(v20) = v15;
      v15 = (unsigned __int8)v15;
      LOBYTE(v16) = result + v19[(unsigned __int8)v15];
      HIBYTE(v20) = v16;
      v16 = (unsigned __int8)v16;
      v17 = v19[(unsigned __int8)v15];
      v19[v15] = v19[(unsigned __int8)v16];
      v19[v16] = v17;
      v14 = v20;
      result = HIBYTE(v20);
      v18 = *v6++;
      *v5++ = v19[(unsigned __int8)(v19[HIBYTE(v20)] + v19[(unsigned __int8)v20])] ^ v18;
    }
    while ( v7 );
  }
  return result;
}

int sub_258C(char* result, int a2, char* a3, char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*((unsigned char*)a4 + v7 % a5)) ^ (*((unsigned char*)a3 + v7) - a6);
            *(char *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}


char* sub_254C(char *result, int a2, unsigned char *a3, char* a4, int a5, char a6)
{
    unsigned int v6; // r3
    unsigned int v7; // t1

    if ( a2 )
    {
        v6 = a3[a2 - 1];
        do
        {
            v7 = *a3++;
            --a2;
            *result++ = ((char)v7 << a6) | (v6 >> (8 - a6));
            v6 = v7;
        }
        while ( a2 );
    }
    return result;
}

int sub_239C(char *a1, int a2, char *a3, char* a4, unsigned int a5)
{
    char *v5; // r11
    char *v6; // r10
    int v7; // r5
    int v8; // r0
    unsigned int v9; // r7
    int v10; // r6
    int v11; // r8
    int result; // r0
    int v13; // r1
    char v14; // r1
    int v15; // r1
    int v16; // r0
    char v17; // r2
    char v18; // t1
    char v19[256]; // [sp+8h] [bp-128h]
    short v20; // [sp+108h] [bp-28h]

    v5 = a1;
    v6 = a3;
    v7 = a2;
    v8 = 0;
    do
    {
        v19[v8] = v8;
        ++v8;
    }
    while ( v8 != 256 );
    v9 = 0;
    v10 = 0;
    v20 = 0;
    do
    {
        v11 = (unsigned char)v19[v9];
        result = *(unsigned char *)(a4 + v9 % a5) + v11;
        v13 = (unsigned char)(result + v10);
        v19[v9] = v19[v13];
        v19[v13] = v11;
        ++v9;
        v10 += result;
    }
    while ( v9 != 256 );
    if ( v7 )
    {
        LOBYTE(result) = HIBYTE(v20);
        v14 = v20;
        do
        {
            LOBYTE(v15) = v14 + 1;
            --v7;
            LOBYTE(v20) = v15;
            v15 = (unsigned char)v15;
            LOBYTE(v16) = result + v19[(unsigned char)v15];
            HIBYTE(v20) = v16;
            v16 = (unsigned char)v16;
            v17 = v19[(unsigned char)v15];
            v19[v15] = v19[(unsigned char)v16];
            v19[v16] = v17;
            v14 = v20;
            result = HIBYTE(v20);
            v18 = *v6++;
            *v5++ = v19[(unsigned char)(v19[HIBYTE(v20)] + v19[(unsigned char)v20])] ^ v18;
        }
        while ( v7 );
    }
    return result;
}

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
            *(char* *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}

int main()
{
    unsigned char unk_44FC[1] = {0x00};

    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("v0:%s\n",(char*)unk_62D7);

    char unk_62EF[128];
    unsigned char unk_448B[8] = {0x01,0x49,0x34,0x72,0x03,0x4E,0xB8,0x00};
    unsigned char unk_4488[3] = {0x6D,0x37,0x00};
    sub_24F4(unk_62EF, 7, unk_448B, unk_4488, 2u, 213);
    printf("dword_6294:%s\n",(char*)unk_62EF);

    char unk_630C[128] = {0};
    unsigned char unk_44F3[9] = {0xE6,0xCF,0xCF,0x89,0xBB,0x16,0x65,0x71,0x00};
    sub_239C(unk_630C, 8, unk_44F3, "LNAt", 4u);
    printf("dword_6298:%s\n",(char*)unk_630C);

    char unk_62DD[128] ={0};
    unsigned char unk_44AC[7] = {0x30,0xB4,0x7D,0x77,0x9C,0xA5,0x00};
    sub_239C(unk_62DD, 6, unk_44AC, "cOXt", 4u);
    printf("dword_629C:%s\n",(char*)unk_62DD);

    char unk_62E3[128];
    unsigned char unk_4481[7] = {0xA9,0xB5,0xB8,0xB7,0xC1,0x55,0x00};
    sub_24F4(unk_62E3, 6, unk_4481, "BMT", 3u, 1);
    printf("dword_62A0 :%s\n",(char*)unk_62E3);

    char unk_62F6[128] ={0};
    unsigned char unk_44C4[8] = {0x45,0xEB,0x5A,0x11,0x75,0x7E,0x4E,0x00};
    unsigned char unk_44C1[3] = {0x47,0x21,0x00};
    sub_239C(unk_62F6, 7, unk_44C4, unk_44C1,2u);
    printf("dword_62A4:%s\n",(char*)unk_62F6);

    char unk_62FD[128];
    unsigned char unk_44CC[8] = {0xB9,0xB9,0xB1,0x30,0x37,0x33,0x80,0x00};
    sub_254C(unk_62FD, 7, unk_44CC, unk_44FC, 0, 1);
    printf("dword_62A8:%s\n",(char*)unk_62FD);

    char unk_62CC[128];
    unsigned char unk_44A1[6] = {0xB5,0x34,0x36,0x36,0x80,0x00};
    sub_254C(unk_62CC, 5, unk_44A1, unk_44FC, 0, 1);
    printf("dword_62AC:%s\n",(char*)unk_62CC);

    unsigned char unk_44FD[7] = {0x39,0xB6,0xB2,0x32,0x38,0x80,0x00};
    char unk_62E9[128];
    sub_254C(unk_62E9, 6, unk_44FD, unk_44FC, 0, 1);
    printf("dword_62B0:%s\n",(char*)unk_62E9);

    char unk_633A[128];
    sub_258C(unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4u, 1);
    printf("dword_62B4:%s\n",(char*)unk_633A);

    char unk_631C[128];
    unsigned char unk_44E4[10] = {0x23,0x18,0xCA,0x21,0x14,0xDF,0x1D,0x14,0x3C,0x00};
    unsigned char unk_44E0[4] = {0x37,0x3F,0x73,0x00};
    sub_258C(unk_631C, 9, unk_44E4, unk_44E0, 3u, 201);
    printf("dword_62B8:%s\n",(char*)unk_631C);

    char unk_632F[128];
    unsigned char unk_44D4[12] = {0xB1,0xB0,0x31,0xB4,0x32,0x33,0xB6,0xBA,0x39,0x34,0x80,0x00};
    sub_254C(unk_632F, 11, unk_44D4, unk_44FC, 0, 1);
    printf("dword_62BC:%s\n",(char*)unk_632F);

    char unk_6314[128];
    unsigned char unk_44B8[9] = {0xFD,0xFF,0xC1,0xDA,0x05,0xBD,0x1A,0x2C,0x00};
    sub_258C(unk_6314, 8, unk_44B8, ".6gq", 4u, 187);
    printf("dword_62C0:%s\n",(char*)unk_6314);

    return 0;
}

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
  char* v6; // r7
  unsigned int v7; // r4

  v6 = result;
  if ( a2 )
  {
    v7 = 0;
    do
    {
      result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
      *(char* *)(v6 + v7++) = result;
    }
    while ( a2 != v7 );
  }
  return result;
}

int main()
{
    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("unk_62D7:%s\n",(char*)unk_62D7);
    return 0;
}
代码运行结果如下:

unk_62D7:dlsym
果然不出所料啊,v0就是dlsym函数的指针,添加所有的解密函数,做一个解密小程序代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if defined(__GNUC__)
typedef          long long ll;
typedef unsigned long long ull;
#define __int64 long long
#define __int32 int
#define __int16 short
#define __int8  char
#define MAKELL(num) num ## LL
#define FMT_64 "ll"
#elif defined(_MSC_VER)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "I64"
#elif defined (__BORLANDC__)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "L"
#else
#error "unknown compiler"
#endif
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;

typedef          char   int8;
typedef   signed char   sint8;
typedef unsigned char   uint8;
typedef          short  int16;
typedef   signed short  sint16;
typedef unsigned short  uint16;
typedef          int    int32;
typedef   signed int    sint32;
typedef unsigned int    uint32;
typedef ll              int64;
typedef ll              sint64;
typedef ull             uint64;

// Partially defined types:
#define _BYTE  uint8
#define _WORD  uint16
#define _DWORD uint32
#define _QWORD uint64
#if !defined(_MSC_VER)
#define _LONGLONG __int128
#endif

#ifndef _WINDOWS_
typedef int8 BYTE;
typedef int16 WORD;
typedef int32 DWORD;
typedef int32 LONG;
#endif
typedef int64 QWORD;
#ifndef __cplusplus
typedef int bool;       // we want to use bool in our C programs
#endif

// Some convenience macros to make partial accesses nicer
// first unsigned macros:
#define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
#define LOWORD(x)   (*((_WORD*)&(x)))   // low word
#define LODWORD(x)  (*((_DWORD*)&(x)))  // low dword
#define HIBYTE(x)   (*((_BYTE*)&(x)+1))
#define HIWORD(x)   (*((_WORD*)&(x)+1))
#define HIDWORD(x)  (*((_DWORD*)&(x)+1))
#define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
#define WORDn(x, n)   (*((_WORD*)&(x)+n))
#define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
#define BYTE2(x)   BYTEn(x,  2)
#define BYTE3(x)   BYTEn(x,  3)
#define BYTE4(x)   BYTEn(x,  4)
#define BYTE5(x)   BYTEn(x,  5)
#define BYTE6(x)   BYTEn(x,  6)
#define BYTE7(x)   BYTEn(x,  7)
#define BYTE8(x)   BYTEn(x,  8)
#define BYTE9(x)   BYTEn(x,  9)
#define BYTE10(x)  BYTEn(x, 10)
#define BYTE11(x)  BYTEn(x, 11)
#define BYTE12(x)  BYTEn(x, 12)
#define BYTE13(x)  BYTEn(x, 13)
#define BYTE14(x)  BYTEn(x, 14)
#define BYTE15(x)  BYTEn(x, 15)
#define WORD1(x)   WORDn(x,  1)
#define WORD2(x)   WORDn(x,  2)         // third word of the object, unsigned
#define WORD3(x)   WORDn(x,  3)
#define WORD4(x)   WORDn(x,  4)
#define WORD5(x)   WORDn(x,  5)
#define WORD6(x)   WORDn(x,  6)
#define WORD7(x)   WORDn(x,  7)

// now signed macros (the same but with sign extension)
#define SLOBYTE(x)   (*((int8*)&(x)))
#define SLOWORD(x)   (*((int16*)&(x)))
#define SLODWORD(x)  (*((int32*)&(x)))
#define SHIBYTE(x)   (*((int8*)&(x)+1))
#define SHIWORD(x)   (*((int16*)&(x)+1))
#define SHIDWORD(x)  (*((int32*)&(x)+1))
#define SBYTEn(x, n)   (*((int8*)&(x)+n))
#define SWORDn(x, n)   (*((int16*)&(x)+n))
#define SBYTE1(x)   SBYTEn(x,  1)
#define SBYTE2(x)   SBYTEn(x,  2)
#define SBYTE3(x)   SBYTEn(x,  3)
#define SBYTE4(x)   SBYTEn(x,  4)
#define SBYTE5(x)   SBYTEn(x,  5)
#define SBYTE6(x)   SBYTEn(x,  6)
#define SBYTE7(x)   SBYTEn(x,  7)
#define SBYTE8(x)   SBYTEn(x,  8)
#define SBYTE9(x)   SBYTEn(x,  9)
#define SBYTE10(x)  SBYTEn(x, 10)
#define SBYTE11(x)  SBYTEn(x, 11)
#define SBYTE12(x)  SBYTEn(x, 12)
#define SBYTE13(x)  SBYTEn(x, 13)
#define SBYTE14(x)  SBYTEn(x, 14)
#define SBYTE15(x)  SBYTEn(x, 15)
#define SWORD1(x)   SWORDn(x,  1)
#define SWORD2(x)   SWORDn(x,  2)
#define SWORD3(x)   SWORDn(x,  3)
#define SWORD4(x)   SWORDn(x,  4)
#define SWORD5(x)   SWORDn(x,  5)
#define SWORD6(x)   SWORDn(x,  6)
#define SWORD7(x)   SWORDn(x,  7)


// Helper functions to represent some assembly instructions.

#ifdef __cplusplus

// Fill memory block with an integer value
inline void memset32(void *ptr, uint32 value, int count)
{
    uint32 *p = (uint32 *)ptr;
    for ( int i=0; i < count; i++ )
        *p++ = value;
}

// Generate a reference to pair of operands
template<class T>  int16 __PAIR__( int8  high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); }
template<class T>  int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); }
template<class T>  int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); }
template<class T> uint16 __PAIR__(uint8  high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); }
template<class T> uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); }
template<class T> uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); }

// rotate left
template<class T> T __ROL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T high = value >> (nbits - count);
    value <<= count;
    value |= high;
    return value;
}

// rotate right
template<class T> T __ROR__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T low = value << (nbits - count);
    value >>= count;
    value |= low;
    return value;
}

// carry flag of left shift
template<class T> int8 __MKCSHL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    return (value >> (nbits-count)) & 1;
}

// carry flag of right shift
template<class T> int8 __MKCSHR__(T value, uint count)
{
    return (value >> (count-1)) & 1;
}

// sign flag
template<class T> int8 __SETS__(T x)
{
    if ( sizeof(T) == 1 )
        return int8(x) < 0;
    if ( sizeof(T) == 2 )
        return int16(x) < 0;
    if ( sizeof(T) == 4 )
        return int32(x) < 0;
    return int64(x) < 0;
}

// overflow flag of subtraction (x-y)
template<class T, class U> int8 __OFSUB__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
    }
}

// overflow flag of addition (x+y)
template<class T, class U> int8 __OFADD__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
    }
}

// carry flag of subtraction (x-y)
template<class T, class U> int8 __CFSUB__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) < uint8(y);
    if ( size == 2 )
        return uint16(x) < uint16(y);
    if ( size == 4 )
        return uint32(x) < uint32(y);
    return uint64(x) < uint64(y);
}

// carry flag of addition (x+y)
template<class T, class U> int8 __CFADD__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) > uint8(x+y);
    if ( size == 2 )
        return uint16(x) > uint16(x+y);
    if ( size == 4 )
        return uint32(x) > uint32(x+y);
    return uint64(x) > uint64(x+y);
}

#else
// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((uint64)(high)<<sizeof(high)*8) | low)
// For C, we just provide macros, they are not quite correct.
#define __ROL__(x, y) __rotl__(x, y)      // Rotate left
#define __ROR__(x, y) __rotr__(x, y)      // Rotate right
#define __CFSHL__(x, y) invalid_operation // Generate carry flag for (x<<y)
#define __CFSHR__(x, y) invalid_operation // Generate carry flag for (x>>y)
#define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y)
#define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y)
#define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y)
#define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y)
#endif

// No definition for rcl/rcr because the carry flag is unknown
#define __RCL__(x, y)    invalid_operation // Rotate left thru carry
#define __RCR__(x, y)    invalid_operation // Rotate right thru carry
#define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL
#define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR
#define __SETP__(x, y)   invalid_operation // Generate parity flag for (x-y)

// In the decompilation listing there are some objects declarared as _UNKNOWN
// because we could not determine their types. Since the C compiler does not
// accept void item declarations, we replace them by anything of our choice,
// for example a char:

#define _UNKNOWN char

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

int __fastcall sub_239C(_BYTE *a1, int a2, char *a3, int a4, unsigned int a5)
{
  _BYTE *v5; // r11
  char *v6; // r10
  int v7; // r5
  int v8; // r0
  unsigned int v9; // r7
  char v10; // r6
  int v11; // r8
  int result; // r0
  int v13; // r1
  char v14; // r1
  int v15; // r1
  int v16; // r0
  char v17; // r2
  char v18; // t1
  char v19[256]; // [sp+8h] [bp-128h]
  __int16 v20; // [sp+108h] [bp-28h]

  v5 = a1;
  v6 = a3;
  v7 = a2;
  v8 = 0;
  do
  {
    v19[v8] = v8;
    ++v8;
  }
  while ( v8 != 256 );
  v9 = 0;
  v10 = 0;
  v20 = 0;
  do
  {
    v11 = (unsigned __int8)v19[v9];
    result = *(unsigned __int8 *)(a4 + v9 % a5) + v11;
    v13 = (unsigned __int8)(result + v10);
    v19[v9] = v19[v13];
    v19[v13] = v11;
    ++v9;
    v10 += result;
  }
  while ( v9 != 256 );
  if ( v7 )
  {
    LOBYTE(result) = HIBYTE(v20);
    v14 = v20;
    do
    {
      LOBYTE(v15) = v14 + 1;
      --v7;
      LOBYTE(v20) = v15;
      v15 = (unsigned __int8)v15;
      LOBYTE(v16) = result + v19[(unsigned __int8)v15];
      HIBYTE(v20) = v16;
      v16 = (unsigned __int8)v16;
      v17 = v19[(unsigned __int8)v15];
      v19[v15] = v19[(unsigned __int8)v16];
      v19[v16] = v17;
      v14 = v20;
      result = HIBYTE(v20);
      v18 = *v6++;
      *v5++ = v19[(unsigned __int8)(v19[HIBYTE(v20)] + v19[(unsigned __int8)v20])] ^ v18;
    }
    while ( v7 );
  }
  return result;
}

int sub_258C(char* result, int a2, char* a3, char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*((unsigned char*)a4 + v7 % a5)) ^ (*((unsigned char*)a3 + v7) - a6);
            *(char *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}


char* sub_254C(char *result, int a2, unsigned char *a3, char* a4, int a5, char a6)
{
    unsigned int v6; // r3
    unsigned int v7; // t1

    if ( a2 )
    {
        v6 = a3[a2 - 1];
        do
        {
            v7 = *a3++;
            --a2;
            *result++ = ((char)v7 << a6) | (v6 >> (8 - a6));
            v6 = v7;
        }
        while ( a2 );
    }
    return result;
}

int sub_239C(char *a1, int a2, char *a3, char* a4, unsigned int a5)
{
    char *v5; // r11
    char *v6; // r10
    int v7; // r5
    int v8; // r0
    unsigned int v9; // r7
    int v10; // r6
    int v11; // r8
    int result; // r0
    int v13; // r1
    char v14; // r1
    int v15; // r1
    int v16; // r0
    char v17; // r2
    char v18; // t1
    char v19[256]; // [sp+8h] [bp-128h]
    short v20; // [sp+108h] [bp-28h]

    v5 = a1;
    v6 = a3;
    v7 = a2;
    v8 = 0;
    do
    {
        v19[v8] = v8;
        ++v8;
    }
    while ( v8 != 256 );
    v9 = 0;
    v10 = 0;
    v20 = 0;
    do
    {
        v11 = (unsigned char)v19[v9];
        result = *(unsigned char *)(a4 + v9 % a5) + v11;
        v13 = (unsigned char)(result + v10);
        v19[v9] = v19[v13];
        v19[v13] = v11;
        ++v9;
        v10 += result;
    }
    while ( v9 != 256 );
    if ( v7 )
    {
        LOBYTE(result) = HIBYTE(v20);
        v14 = v20;
        do
        {
            LOBYTE(v15) = v14 + 1;
            --v7;
            LOBYTE(v20) = v15;
            v15 = (unsigned char)v15;
            LOBYTE(v16) = result + v19[(unsigned char)v15];
            HIBYTE(v20) = v16;
            v16 = (unsigned char)v16;
            v17 = v19[(unsigned char)v15];
            v19[v15] = v19[(unsigned char)v16];
            v19[v16] = v17;
            v14 = v20;
            result = HIBYTE(v20);
            v18 = *v6++;
            *v5++ = v19[(unsigned char)(v19[HIBYTE(v20)] + v19[(unsigned char)v20])] ^ v18;
        }
        while ( v7 );
    }
    return result;
}

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
            *(char* *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}

int main()
{
    unsigned char unk_44FC[1] = {0x00};

    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("v0:%s\n",(char*)unk_62D7);

    char unk_62EF[128];
    unsigned char unk_448B[8] = {0x01,0x49,0x34,0x72,0x03,0x4E,0xB8,0x00};
    unsigned char unk_4488[3] = {0x6D,0x37,0x00};
    sub_24F4(unk_62EF, 7, unk_448B, unk_4488, 2u, 213);
    printf("dword_6294:%s\n",(char*)unk_62EF);

    char unk_630C[128] = {0};
    unsigned char unk_44F3[9] = {0xE6,0xCF,0xCF,0x89,0xBB,0x16,0x65,0x71,0x00};
    sub_239C(unk_630C, 8, unk_44F3, "LNAt", 4u);
    printf("dword_6298:%s\n",(char*)unk_630C);

    char unk_62DD[128] ={0};
    unsigned char unk_44AC[7] = {0x30,0xB4,0x7D,0x77,0x9C,0xA5,0x00};
    sub_239C(unk_62DD, 6, unk_44AC, "cOXt", 4u);
    printf("dword_629C:%s\n",(char*)unk_62DD);

    char unk_62E3[128];
    unsigned char unk_4481[7] = {0xA9,0xB5,0xB8,0xB7,0xC1,0x55,0x00};
    sub_24F4(unk_62E3, 6, unk_4481, "BMT", 3u, 1);
    printf("dword_62A0 :%s\n",(char*)unk_62E3);

    char unk_62F6[128] ={0};
    unsigned char unk_44C4[8] = {0x45,0xEB,0x5A,0x11,0x75,0x7E,0x4E,0x00};
    unsigned char unk_44C1[3] = {0x47,0x21,0x00};
    sub_239C(unk_62F6, 7, unk_44C4, unk_44C1,2u);
    printf("dword_62A4:%s\n",(char*)unk_62F6);

    char unk_62FD[128];
    unsigned char unk_44CC[8] = {0xB9,0xB9,0xB1,0x30,0x37,0x33,0x80,0x00};
    sub_254C(unk_62FD, 7, unk_44CC, unk_44FC, 0, 1);
    printf("dword_62A8:%s\n",(char*)unk_62FD);

    char unk_62CC[128];
    unsigned char unk_44A1[6] = {0xB5,0x34,0x36,0x36,0x80,0x00};
    sub_254C(unk_62CC, 5, unk_44A1, unk_44FC, 0, 1);
    printf("dword_62AC:%s\n",(char*)unk_62CC);

    unsigned char unk_44FD[7] = {0x39,0xB6,0xB2,0x32,0x38,0x80,0x00};
    char unk_62E9[128];
    sub_254C(unk_62E9, 6, unk_44FD, unk_44FC, 0, 1);
    printf("dword_62B0:%s\n",(char*)unk_62E9);

    char unk_633A[128];
    sub_258C(unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4u, 1);
    printf("dword_62B4:%s\n",(char*)unk_633A);

    char unk_631C[128];
    unsigned char unk_44E4[10] = {0x23,0x18,0xCA,0x21,0x14,0xDF,0x1D,0x14,0x3C,0x00};
    unsigned char unk_44E0[4] = {0x37,0x3F,0x73,0x00};
    sub_258C(unk_631C, 9, unk_44E4, unk_44E0, 3u, 201);
    printf("dword_62B8:%s\n",(char*)unk_631C);

    char unk_632F[128];
    unsigned char unk_44D4[12] = {0xB1,0xB0,0x31,0xB4,0x32,0x33,0xB6,0xBA,0x39,0x34,0x80,0x00};
    sub_254C(unk_632F, 11, unk_44D4, unk_44FC, 0, 1);
    printf("dword_62BC:%s\n",(char*)unk_632F);

    char unk_6314[128];
    unsigned char unk_44B8[9] = {0xFD,0xFF,0xC1,0xDA,0x05,0xBD,0x1A,0x2C,0x00};
    sub_258C(unk_6314, 8, unk_44B8, ".6gq", 4u, 187);
    printf("dword_62C0:%s\n",(char*)unk_6314);

    return 0;
}

unk_62D7:dlsym
果然不出所料啊,v0就是dlsym函数的指针,添加所有的解密函数,做一个解密小程序代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if defined(__GNUC__)
typedef          long long ll;
typedef unsigned long long ull;
#define __int64 long long
#define __int32 int
#define __int16 short
#define __int8  char
#define MAKELL(num) num ## LL
#define FMT_64 "ll"
#elif defined(_MSC_VER)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "I64"
#elif defined (__BORLANDC__)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "L"
#else
#error "unknown compiler"
#endif
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;

typedef          char   int8;
typedef   signed char   sint8;
typedef unsigned char   uint8;
typedef          short  int16;
typedef   signed short  sint16;
typedef unsigned short  uint16;
typedef          int    int32;
typedef   signed int    sint32;
typedef unsigned int    uint32;
typedef ll              int64;
typedef ll              sint64;
typedef ull             uint64;

// Partially defined types:
#define _BYTE  uint8
#define _WORD  uint16
#define _DWORD uint32
#define _QWORD uint64
#if !defined(_MSC_VER)
#define _LONGLONG __int128
#endif

#ifndef _WINDOWS_
typedef int8 BYTE;
typedef int16 WORD;
typedef int32 DWORD;
typedef int32 LONG;
#endif
typedef int64 QWORD;
#ifndef __cplusplus
typedef int bool;       // we want to use bool in our C programs
#endif

// Some convenience macros to make partial accesses nicer
// first unsigned macros:
#define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
#define LOWORD(x)   (*((_WORD*)&(x)))   // low word
#define LODWORD(x)  (*((_DWORD*)&(x)))  // low dword
#define HIBYTE(x)   (*((_BYTE*)&(x)+1))
#define HIWORD(x)   (*((_WORD*)&(x)+1))
#define HIDWORD(x)  (*((_DWORD*)&(x)+1))
#define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
#define WORDn(x, n)   (*((_WORD*)&(x)+n))
#define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
#define BYTE2(x)   BYTEn(x,  2)
#define BYTE3(x)   BYTEn(x,  3)
#define BYTE4(x)   BYTEn(x,  4)
#define BYTE5(x)   BYTEn(x,  5)
#define BYTE6(x)   BYTEn(x,  6)
#define BYTE7(x)   BYTEn(x,  7)
#define BYTE8(x)   BYTEn(x,  8)
#define BYTE9(x)   BYTEn(x,  9)
#define BYTE10(x)  BYTEn(x, 10)
#define BYTE11(x)  BYTEn(x, 11)
#define BYTE12(x)  BYTEn(x, 12)
#define BYTE13(x)  BYTEn(x, 13)
#define BYTE14(x)  BYTEn(x, 14)
#define BYTE15(x)  BYTEn(x, 15)
#define WORD1(x)   WORDn(x,  1)
#define WORD2(x)   WORDn(x,  2)         // third word of the object, unsigned
#define WORD3(x)   WORDn(x,  3)
#define WORD4(x)   WORDn(x,  4)
#define WORD5(x)   WORDn(x,  5)
#define WORD6(x)   WORDn(x,  6)
#define WORD7(x)   WORDn(x,  7)

// now signed macros (the same but with sign extension)
#define SLOBYTE(x)   (*((int8*)&(x)))
#define SLOWORD(x)   (*((int16*)&(x)))
#define SLODWORD(x)  (*((int32*)&(x)))
#define SHIBYTE(x)   (*((int8*)&(x)+1))
#define SHIWORD(x)   (*((int16*)&(x)+1))
#define SHIDWORD(x)  (*((int32*)&(x)+1))
#define SBYTEn(x, n)   (*((int8*)&(x)+n))
#define SWORDn(x, n)   (*((int16*)&(x)+n))
#define SBYTE1(x)   SBYTEn(x,  1)
#define SBYTE2(x)   SBYTEn(x,  2)
#define SBYTE3(x)   SBYTEn(x,  3)
#define SBYTE4(x)   SBYTEn(x,  4)
#define SBYTE5(x)   SBYTEn(x,  5)
#define SBYTE6(x)   SBYTEn(x,  6)
#define SBYTE7(x)   SBYTEn(x,  7)
#define SBYTE8(x)   SBYTEn(x,  8)
#define SBYTE9(x)   SBYTEn(x,  9)
#define SBYTE10(x)  SBYTEn(x, 10)
#define SBYTE11(x)  SBYTEn(x, 11)
#define SBYTE12(x)  SBYTEn(x, 12)
#define SBYTE13(x)  SBYTEn(x, 13)
#define SBYTE14(x)  SBYTEn(x, 14)
#define SBYTE15(x)  SBYTEn(x, 15)
#define SWORD1(x)   SWORDn(x,  1)
#define SWORD2(x)   SWORDn(x,  2)
#define SWORD3(x)   SWORDn(x,  3)
#define SWORD4(x)   SWORDn(x,  4)
#define SWORD5(x)   SWORDn(x,  5)
#define SWORD6(x)   SWORDn(x,  6)
#define SWORD7(x)   SWORDn(x,  7)


// Helper functions to represent some assembly instructions.

#ifdef __cplusplus

// Fill memory block with an integer value
inline void memset32(void *ptr, uint32 value, int count)
{
    uint32 *p = (uint32 *)ptr;
    for ( int i=0; i < count; i++ )
        *p++ = value;
}

// Generate a reference to pair of operands
template<class T>  int16 __PAIR__( int8  high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); }
template<class T>  int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); }
template<class T>  int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); }
template<class T> uint16 __PAIR__(uint8  high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); }
template<class T> uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); }
template<class T> uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); }

// rotate left
template<class T> T __ROL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T high = value >> (nbits - count);
    value <<= count;
    value |= high;
    return value;
}

// rotate right
template<class T> T __ROR__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T low = value << (nbits - count);
    value >>= count;
    value |= low;
    return value;
}

// carry flag of left shift
template<class T> int8 __MKCSHL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    return (value >> (nbits-count)) & 1;
}

// carry flag of right shift
template<class T> int8 __MKCSHR__(T value, uint count)
{
    return (value >> (count-1)) & 1;
}

// sign flag
template<class T> int8 __SETS__(T x)
{
    if ( sizeof(T) == 1 )
        return int8(x) < 0;
    if ( sizeof(T) == 2 )
        return int16(x) < 0;
    if ( sizeof(T) == 4 )
        return int32(x) < 0;
    return int64(x) < 0;
}

// overflow flag of subtraction (x-y)
template<class T, class U> int8 __OFSUB__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
    }
}

// overflow flag of addition (x+y)
template<class T, class U> int8 __OFADD__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
    }
}

// carry flag of subtraction (x-y)
template<class T, class U> int8 __CFSUB__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) < uint8(y);
    if ( size == 2 )
        return uint16(x) < uint16(y);
    if ( size == 4 )
        return uint32(x) < uint32(y);
    return uint64(x) < uint64(y);
}

// carry flag of addition (x+y)
template<class T, class U> int8 __CFADD__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) > uint8(x+y);
    if ( size == 2 )
        return uint16(x) > uint16(x+y);
    if ( size == 4 )
        return uint32(x) > uint32(x+y);
    return uint64(x) > uint64(x+y);
}

#else
// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((uint64)(high)<<sizeof(high)*8) | low)
// For C, we just provide macros, they are not quite correct.
#define __ROL__(x, y) __rotl__(x, y)      // Rotate left
#define __ROR__(x, y) __rotr__(x, y)      // Rotate right
#define __CFSHL__(x, y) invalid_operation // Generate carry flag for (x<<y)
#define __CFSHR__(x, y) invalid_operation // Generate carry flag for (x>>y)
#define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y)
#define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y)
#define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y)
#define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y)
#endif

// No definition for rcl/rcr because the carry flag is unknown
#define __RCL__(x, y)    invalid_operation // Rotate left thru carry
#define __RCR__(x, y)    invalid_operation // Rotate right thru carry
#define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL
#define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR
#define __SETP__(x, y)   invalid_operation // Generate parity flag for (x-y)

// In the decompilation listing there are some objects declarared as _UNKNOWN
// because we could not determine their types. Since the C compiler does not
// accept void item declarations, we replace them by anything of our choice,
// for example a char:

#define _UNKNOWN char

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

int __fastcall sub_239C(_BYTE *a1, int a2, char *a3, int a4, unsigned int a5)
{
  _BYTE *v5; // r11
  char *v6; // r10
  int v7; // r5
  int v8; // r0
  unsigned int v9; // r7
  char v10; // r6
  int v11; // r8
  int result; // r0
  int v13; // r1
  char v14; // r1
  int v15; // r1
  int v16; // r0
  char v17; // r2
  char v18; // t1
  char v19[256]; // [sp+8h] [bp-128h]
  __int16 v20; // [sp+108h] [bp-28h]

  v5 = a1;
  v6 = a3;
  v7 = a2;
  v8 = 0;
  do
  {
    v19[v8] = v8;
    ++v8;
  }
  while ( v8 != 256 );
  v9 = 0;
  v10 = 0;
  v20 = 0;
  do
  {
    v11 = (unsigned __int8)v19[v9];
    result = *(unsigned __int8 *)(a4 + v9 % a5) + v11;
    v13 = (unsigned __int8)(result + v10);
    v19[v9] = v19[v13];
    v19[v13] = v11;
    ++v9;
    v10 += result;
  }
  while ( v9 != 256 );
  if ( v7 )
  {
    LOBYTE(result) = HIBYTE(v20);
    v14 = v20;
    do
    {
      LOBYTE(v15) = v14 + 1;
      --v7;
      LOBYTE(v20) = v15;
      v15 = (unsigned __int8)v15;
      LOBYTE(v16) = result + v19[(unsigned __int8)v15];
      HIBYTE(v20) = v16;
      v16 = (unsigned __int8)v16;
      v17 = v19[(unsigned __int8)v15];
      v19[v15] = v19[(unsigned __int8)v16];
      v19[v16] = v17;
      v14 = v20;
      result = HIBYTE(v20);
      v18 = *v6++;
      *v5++ = v19[(unsigned __int8)(v19[HIBYTE(v20)] + v19[(unsigned __int8)v20])] ^ v18;
    }
    while ( v7 );
  }
  return result;
}

int sub_258C(char* result, int a2, char* a3, char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*((unsigned char*)a4 + v7 % a5)) ^ (*((unsigned char*)a3 + v7) - a6);
            *(char *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}


char* sub_254C(char *result, int a2, unsigned char *a3, char* a4, int a5, char a6)
{
    unsigned int v6; // r3
    unsigned int v7; // t1

    if ( a2 )
    {
        v6 = a3[a2 - 1];
        do
        {
            v7 = *a3++;
            --a2;
            *result++ = ((char)v7 << a6) | (v6 >> (8 - a6));
            v6 = v7;
        }
        while ( a2 );
    }
    return result;
}

int sub_239C(char *a1, int a2, char *a3, char* a4, unsigned int a5)
{
    char *v5; // r11
    char *v6; // r10
    int v7; // r5
    int v8; // r0
    unsigned int v9; // r7
    int v10; // r6
    int v11; // r8
    int result; // r0
    int v13; // r1
    char v14; // r1
    int v15; // r1
    int v16; // r0
    char v17; // r2
    char v18; // t1
    char v19[256]; // [sp+8h] [bp-128h]
    short v20; // [sp+108h] [bp-28h]

    v5 = a1;
    v6 = a3;
    v7 = a2;
    v8 = 0;
    do
    {
        v19[v8] = v8;
        ++v8;
    }
    while ( v8 != 256 );
    v9 = 0;
    v10 = 0;
    v20 = 0;
    do
    {
        v11 = (unsigned char)v19[v9];
        result = *(unsigned char *)(a4 + v9 % a5) + v11;
        v13 = (unsigned char)(result + v10);
        v19[v9] = v19[v13];
        v19[v13] = v11;
        ++v9;
        v10 += result;
    }
    while ( v9 != 256 );
    if ( v7 )
    {
        LOBYTE(result) = HIBYTE(v20);
        v14 = v20;
        do
        {
            LOBYTE(v15) = v14 + 1;
            --v7;
            LOBYTE(v20) = v15;
            v15 = (unsigned char)v15;
            LOBYTE(v16) = result + v19[(unsigned char)v15];
            HIBYTE(v20) = v16;
            v16 = (unsigned char)v16;
            v17 = v19[(unsigned char)v15];
            v19[v15] = v19[(unsigned char)v16];
            v19[v16] = v17;
            v14 = v20;
            result = HIBYTE(v20);
            v18 = *v6++;
            *v5++ = v19[(unsigned char)(v19[HIBYTE(v20)] + v19[(unsigned char)v20])] ^ v18;
        }
        while ( v7 );
    }
    return result;
}

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
            *(char* *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}

int main()
{
    unsigned char unk_44FC[1] = {0x00};

    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("v0:%s\n",(char*)unk_62D7);

    char unk_62EF[128];
    unsigned char unk_448B[8] = {0x01,0x49,0x34,0x72,0x03,0x4E,0xB8,0x00};
    unsigned char unk_4488[3] = {0x6D,0x37,0x00};
    sub_24F4(unk_62EF, 7, unk_448B, unk_4488, 2u, 213);
    printf("dword_6294:%s\n",(char*)unk_62EF);

    char unk_630C[128] = {0};
    unsigned char unk_44F3[9] = {0xE6,0xCF,0xCF,0x89,0xBB,0x16,0x65,0x71,0x00};
    sub_239C(unk_630C, 8, unk_44F3, "LNAt", 4u);
    printf("dword_6298:%s\n",(char*)unk_630C);

    char unk_62DD[128] ={0};
    unsigned char unk_44AC[7] = {0x30,0xB4,0x7D,0x77,0x9C,0xA5,0x00};
    sub_239C(unk_62DD, 6, unk_44AC, "cOXt", 4u);
    printf("dword_629C:%s\n",(char*)unk_62DD);

    char unk_62E3[128];
    unsigned char unk_4481[7] = {0xA9,0xB5,0xB8,0xB7,0xC1,0x55,0x00};
    sub_24F4(unk_62E3, 6, unk_4481, "BMT", 3u, 1);
    printf("dword_62A0 :%s\n",(char*)unk_62E3);

    char unk_62F6[128] ={0};
    unsigned char unk_44C4[8] = {0x45,0xEB,0x5A,0x11,0x75,0x7E,0x4E,0x00};
    unsigned char unk_44C1[3] = {0x47,0x21,0x00};
    sub_239C(unk_62F6, 7, unk_44C4, unk_44C1,2u);
    printf("dword_62A4:%s\n",(char*)unk_62F6);

    char unk_62FD[128];
    unsigned char unk_44CC[8] = {0xB9,0xB9,0xB1,0x30,0x37,0x33,0x80,0x00};
    sub_254C(unk_62FD, 7, unk_44CC, unk_44FC, 0, 1);
    printf("dword_62A8:%s\n",(char*)unk_62FD);

    char unk_62CC[128];
    unsigned char unk_44A1[6] = {0xB5,0x34,0x36,0x36,0x80,0x00};
    sub_254C(unk_62CC, 5, unk_44A1, unk_44FC, 0, 1);
    printf("dword_62AC:%s\n",(char*)unk_62CC);

    unsigned char unk_44FD[7] = {0x39,0xB6,0xB2,0x32,0x38,0x80,0x00};
    char unk_62E9[128];
    sub_254C(unk_62E9, 6, unk_44FD, unk_44FC, 0, 1);
    printf("dword_62B0:%s\n",(char*)unk_62E9);

    char unk_633A[128];
    sub_258C(unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4u, 1);
    printf("dword_62B4:%s\n",(char*)unk_633A);

    char unk_631C[128];
    unsigned char unk_44E4[10] = {0x23,0x18,0xCA,0x21,0x14,0xDF,0x1D,0x14,0x3C,0x00};
    unsigned char unk_44E0[4] = {0x37,0x3F,0x73,0x00};
    sub_258C(unk_631C, 9, unk_44E4, unk_44E0, 3u, 201);
    printf("dword_62B8:%s\n",(char*)unk_631C);

    char unk_632F[128];
    unsigned char unk_44D4[12] = {0xB1,0xB0,0x31,0xB4,0x32,0x33,0xB6,0xBA,0x39,0x34,0x80,0x00};
    sub_254C(unk_632F, 11, unk_44D4, unk_44FC, 0, 1);
    printf("dword_62BC:%s\n",(char*)unk_632F);

    char unk_6314[128];
    unsigned char unk_44B8[9] = {0xFD,0xFF,0xC1,0xDA,0x05,0xBD,0x1A,0x2C,0x00};
    sub_258C(unk_6314, 8, unk_44B8, ".6gq", 4u, 187);
    printf("dword_62C0:%s\n",(char*)unk_6314);

    return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if defined(__GNUC__)
typedef          long long ll;
typedef unsigned long long ull;
#define __int64 long long
#define __int32 int
#define __int16 short
#define __int8  char
#define MAKELL(num) num ## LL
#define FMT_64 "ll"
#elif defined(_MSC_VER)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "I64"
#elif defined (__BORLANDC__)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "L"
#else
#error "unknown compiler"
#endif
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;

typedef          char   int8;
typedef   signed char   sint8;
typedef unsigned char   uint8;
typedef          short  int16;
typedef   signed short  sint16;
typedef unsigned short  uint16;
typedef          int    int32;
typedef   signed int    sint32;
typedef unsigned int    uint32;
typedef ll              int64;
typedef ll              sint64;
typedef ull             uint64;

// Partially defined types:
#define _BYTE  uint8
#define _WORD  uint16
#define _DWORD uint32
#define _QWORD uint64
#if !defined(_MSC_VER)
#define _LONGLONG __int128
#endif

#ifndef _WINDOWS_
typedef int8 BYTE;
typedef int16 WORD;
typedef int32 DWORD;
typedef int32 LONG;
#endif
typedef int64 QWORD;
#ifndef __cplusplus
typedef int bool;       // we want to use bool in our C programs
#endif

// Some convenience macros to make partial accesses nicer
// first unsigned macros:
#define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
#define LOWORD(x)   (*((_WORD*)&(x)))   // low word
#define LODWORD(x)  (*((_DWORD*)&(x)))  // low dword
#define HIBYTE(x)   (*((_BYTE*)&(x)+1))
#define HIWORD(x)   (*((_WORD*)&(x)+1))
#define HIDWORD(x)  (*((_DWORD*)&(x)+1))
#define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
#define WORDn(x, n)   (*((_WORD*)&(x)+n))
#define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
#define BYTE2(x)   BYTEn(x,  2)
#define BYTE3(x)   BYTEn(x,  3)
#define BYTE4(x)   BYTEn(x,  4)
#define BYTE5(x)   BYTEn(x,  5)
#define BYTE6(x)   BYTEn(x,  6)
#define BYTE7(x)   BYTEn(x,  7)
#define BYTE8(x)   BYTEn(x,  8)
#define BYTE9(x)   BYTEn(x,  9)
#define BYTE10(x)  BYTEn(x, 10)
#define BYTE11(x)  BYTEn(x, 11)
#define BYTE12(x)  BYTEn(x, 12)
#define BYTE13(x)  BYTEn(x, 13)
#define BYTE14(x)  BYTEn(x, 14)
#define BYTE15(x)  BYTEn(x, 15)
#define WORD1(x)   WORDn(x,  1)
#define WORD2(x)   WORDn(x,  2)         // third word of the object, unsigned
#define WORD3(x)   WORDn(x,  3)
#define WORD4(x)   WORDn(x,  4)
#define WORD5(x)   WORDn(x,  5)
#define WORD6(x)   WORDn(x,  6)
#define WORD7(x)   WORDn(x,  7)

// now signed macros (the same but with sign extension)
#define SLOBYTE(x)   (*((int8*)&(x)))
#define SLOWORD(x)   (*((int16*)&(x)))
#define SLODWORD(x)  (*((int32*)&(x)))
#define SHIBYTE(x)   (*((int8*)&(x)+1))
#define SHIWORD(x)   (*((int16*)&(x)+1))
#define SHIDWORD(x)  (*((int32*)&(x)+1))
#define SBYTEn(x, n)   (*((int8*)&(x)+n))
#define SWORDn(x, n)   (*((int16*)&(x)+n))
#define SBYTE1(x)   SBYTEn(x,  1)
#define SBYTE2(x)   SBYTEn(x,  2)
#define SBYTE3(x)   SBYTEn(x,  3)
#define SBYTE4(x)   SBYTEn(x,  4)
#define SBYTE5(x)   SBYTEn(x,  5)
#define SBYTE6(x)   SBYTEn(x,  6)
#define SBYTE7(x)   SBYTEn(x,  7)
#define SBYTE8(x)   SBYTEn(x,  8)
#define SBYTE9(x)   SBYTEn(x,  9)
#define SBYTE10(x)  SBYTEn(x, 10)
#define SBYTE11(x)  SBYTEn(x, 11)
#define SBYTE12(x)  SBYTEn(x, 12)
#define SBYTE13(x)  SBYTEn(x, 13)
#define SBYTE14(x)  SBYTEn(x, 14)
#define SBYTE15(x)  SBYTEn(x, 15)
#define SWORD1(x)   SWORDn(x,  1)
#define SWORD2(x)   SWORDn(x,  2)
#define SWORD3(x)   SWORDn(x,  3)
#define SWORD4(x)   SWORDn(x,  4)
#define SWORD5(x)   SWORDn(x,  5)
#define SWORD6(x)   SWORDn(x,  6)
#define SWORD7(x)   SWORDn(x,  7)


// Helper functions to represent some assembly instructions.

#ifdef __cplusplus

// Fill memory block with an integer value
inline void memset32(void *ptr, uint32 value, int count)
{
    uint32 *p = (uint32 *)ptr;
    for ( int i=0; i < count; i++ )
        *p++ = value;
}

// Generate a reference to pair of operands
template<class T>  int16 __PAIR__( int8  high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); }
template<class T>  int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); }
template<class T>  int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); }
template<class T> uint16 __PAIR__(uint8  high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); }
template<class T> uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); }
template<class T> uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); }

// rotate left
template<class T> T __ROL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T high = value >> (nbits - count);
    value <<= count;
    value |= high;
    return value;
}

// rotate right
template<class T> T __ROR__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T low = value << (nbits - count);
    value >>= count;
    value |= low;
    return value;
}

// carry flag of left shift
template<class T> int8 __MKCSHL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    return (value >> (nbits-count)) & 1;
}

// carry flag of right shift
template<class T> int8 __MKCSHR__(T value, uint count)
{
    return (value >> (count-1)) & 1;
}

// sign flag
template<class T> int8 __SETS__(T x)
{
    if ( sizeof(T) == 1 )
        return int8(x) < 0;
    if ( sizeof(T) == 2 )
        return int16(x) < 0;
    if ( sizeof(T) == 4 )
        return int32(x) < 0;
    return int64(x) < 0;
}

// overflow flag of subtraction (x-y)
template<class T, class U> int8 __OFSUB__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
    }
}

// overflow flag of addition (x+y)
template<class T, class U> int8 __OFADD__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
    }
}

// carry flag of subtraction (x-y)
template<class T, class U> int8 __CFSUB__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) < uint8(y);
    if ( size == 2 )
        return uint16(x) < uint16(y);
    if ( size == 4 )
        return uint32(x) < uint32(y);
    return uint64(x) < uint64(y);
}

// carry flag of addition (x+y)
template<class T, class U> int8 __CFADD__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) > uint8(x+y);
    if ( size == 2 )
        return uint16(x) > uint16(x+y);
    if ( size == 4 )
        return uint32(x) > uint32(x+y);
    return uint64(x) > uint64(x+y);
}

#else
// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((uint64)(high)<<sizeof(high)*8) | low)
// For C, we just provide macros, they are not quite correct.
#define __ROL__(x, y) __rotl__(x, y)      // Rotate left
#define __ROR__(x, y) __rotr__(x, y)      // Rotate right
#define __CFSHL__(x, y) invalid_operation // Generate carry flag for (x<<y)
#define __CFSHR__(x, y) invalid_operation // Generate carry flag for (x>>y)
#define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y)
#define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y)
#define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y)
#define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y)
#endif

// No definition for rcl/rcr because the carry flag is unknown
#define __RCL__(x, y)    invalid_operation // Rotate left thru carry
#define __RCR__(x, y)    invalid_operation // Rotate right thru carry
#define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL
#define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR
#define __SETP__(x, y)   invalid_operation // Generate parity flag for (x-y)

// In the decompilation listing there are some objects declarared as _UNKNOWN
// because we could not determine their types. Since the C compiler does not
// accept void item declarations, we replace them by anything of our choice,
// for example a char:

#define _UNKNOWN char

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

int __fastcall sub_239C(_BYTE *a1, int a2, char *a3, int a4, unsigned int a5)
{
  _BYTE *v5; // r11
  char *v6; // r10
  int v7; // r5
  int v8; // r0
  unsigned int v9; // r7
  char v10; // r6
  int v11; // r8
  int result; // r0
  int v13; // r1
  char v14; // r1
  int v15; // r1
  int v16; // r0
  char v17; // r2
  char v18; // t1
  char v19[256]; // [sp+8h] [bp-128h]
  __int16 v20; // [sp+108h] [bp-28h]

  v5 = a1;
  v6 = a3;
  v7 = a2;
  v8 = 0;
  do
  {
    v19[v8] = v8;
    ++v8;
  }
  while ( v8 != 256 );
  v9 = 0;
  v10 = 0;
  v20 = 0;
  do
  {
    v11 = (unsigned __int8)v19[v9];
    result = *(unsigned __int8 *)(a4 + v9 % a5) + v11;
    v13 = (unsigned __int8)(result + v10);
    v19[v9] = v19[v13];
    v19[v13] = v11;
    ++v9;
    v10 += result;
  }
  while ( v9 != 256 );
  if ( v7 )
  {
    LOBYTE(result) = HIBYTE(v20);
    v14 = v20;
    do
    {
      LOBYTE(v15) = v14 + 1;
      --v7;
      LOBYTE(v20) = v15;
      v15 = (unsigned __int8)v15;
      LOBYTE(v16) = result + v19[(unsigned __int8)v15];
      HIBYTE(v20) = v16;
      v16 = (unsigned __int8)v16;
      v17 = v19[(unsigned __int8)v15];
      v19[v15] = v19[(unsigned __int8)v16];
      v19[v16] = v17;
      v14 = v20;
      result = HIBYTE(v20);
      v18 = *v6++;
      *v5++ = v19[(unsigned __int8)(v19[HIBYTE(v20)] + v19[(unsigned __int8)v20])] ^ v18;
    }
    while ( v7 );
  }
  return result;
}

int sub_258C(char* result, int a2, char* a3, char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*((unsigned char*)a4 + v7 % a5)) ^ (*((unsigned char*)a3 + v7) - a6);
            *(char *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}


char* sub_254C(char *result, int a2, unsigned char *a3, char* a4, int a5, char a6)
{
    unsigned int v6; // r3
    unsigned int v7; // t1

    if ( a2 )
    {
        v6 = a3[a2 - 1];
        do
        {
            v7 = *a3++;
            --a2;
            *result++ = ((char)v7 << a6) | (v6 >> (8 - a6));
            v6 = v7;
        }
        while ( a2 );
    }
    return result;
}

int sub_239C(char *a1, int a2, char *a3, char* a4, unsigned int a5)
{
    char *v5; // r11
    char *v6; // r10
    int v7; // r5
    int v8; // r0
    unsigned int v9; // r7
    int v10; // r6
    int v11; // r8
    int result; // r0
    int v13; // r1
    char v14; // r1
    int v15; // r1
    int v16; // r0
    char v17; // r2
    char v18; // t1
    char v19[256]; // [sp+8h] [bp-128h]
    short v20; // [sp+108h] [bp-28h]

    v5 = a1;
    v6 = a3;
    v7 = a2;
    v8 = 0;
    do
    {
        v19[v8] = v8;
        ++v8;
    }
    while ( v8 != 256 );
    v9 = 0;
    v10 = 0;
    v20 = 0;
    do
    {
        v11 = (unsigned char)v19[v9];
        result = *(unsigned char *)(a4 + v9 % a5) + v11;
        v13 = (unsigned char)(result + v10);
        v19[v9] = v19[v13];
        v19[v13] = v11;
        ++v9;
        v10 += result;
    }
    while ( v9 != 256 );
    if ( v7 )
    {
        LOBYTE(result) = HIBYTE(v20);
        v14 = v20;
        do
        {
            LOBYTE(v15) = v14 + 1;
            --v7;
            LOBYTE(v20) = v15;
            v15 = (unsigned char)v15;
            LOBYTE(v16) = result + v19[(unsigned char)v15];
            HIBYTE(v20) = v16;
            v16 = (unsigned char)v16;
            v17 = v19[(unsigned char)v15];
            v19[v15] = v19[(unsigned char)v16];
            v19[v16] = v17;
            v14 = v20;
            result = HIBYTE(v20);
            v18 = *v6++;
            *v5++ = v19[(unsigned char)(v19[HIBYTE(v20)] + v19[(unsigned char)v20])] ^ v18;
        }
        while ( v7 );
    }
    return result;
}

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
            *(char* *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}

int main()
{
    unsigned char unk_44FC[1] = {0x00};

    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("v0:%s\n",(char*)unk_62D7);

    char unk_62EF[128];
    unsigned char unk_448B[8] = {0x01,0x49,0x34,0x72,0x03,0x4E,0xB8,0x00};
    unsigned char unk_4488[3] = {0x6D,0x37,0x00};
    sub_24F4(unk_62EF, 7, unk_448B, unk_4488, 2u, 213);
    printf("dword_6294:%s\n",(char*)unk_62EF);

    char unk_630C[128] = {0};
    unsigned char unk_44F3[9] = {0xE6,0xCF,0xCF,0x89,0xBB,0x16,0x65,0x71,0x00};
    sub_239C(unk_630C, 8, unk_44F3, "LNAt", 4u);
    printf("dword_6298:%s\n",(char*)unk_630C);

    char unk_62DD[128] ={0};
    unsigned char unk_44AC[7] = {0x30,0xB4,0x7D,0x77,0x9C,0xA5,0x00};
    sub_239C(unk_62DD, 6, unk_44AC, "cOXt", 4u);
    printf("dword_629C:%s\n",(char*)unk_62DD);

    char unk_62E3[128];
    unsigned char unk_4481[7] = {0xA9,0xB5,0xB8,0xB7,0xC1,0x55,0x00};
    sub_24F4(unk_62E3, 6, unk_4481, "BMT", 3u, 1);
    printf("dword_62A0 :%s\n",(char*)unk_62E3);

    char unk_62F6[128] ={0};
    unsigned char unk_44C4[8] = {0x45,0xEB,0x5A,0x11,0x75,0x7E,0x4E,0x00};
    unsigned char unk_44C1[3] = {0x47,0x21,0x00};
    sub_239C(unk_62F6, 7, unk_44C4, unk_44C1,2u);
    printf("dword_62A4:%s\n",(char*)unk_62F6);

    char unk_62FD[128];
    unsigned char unk_44CC[8] = {0xB9,0xB9,0xB1,0x30,0x37,0x33,0x80,0x00};
    sub_254C(unk_62FD, 7, unk_44CC, unk_44FC, 0, 1);
    printf("dword_62A8:%s\n",(char*)unk_62FD);

    char unk_62CC[128];
    unsigned char unk_44A1[6] = {0xB5,0x34,0x36,0x36,0x80,0x00};
    sub_254C(unk_62CC, 5, unk_44A1, unk_44FC, 0, 1);
    printf("dword_62AC:%s\n",(char*)unk_62CC);

    unsigned char unk_44FD[7] = {0x39,0xB6,0xB2,0x32,0x38,0x80,0x00};
    char unk_62E9[128];
    sub_254C(unk_62E9, 6, unk_44FD, unk_44FC, 0, 1);
    printf("dword_62B0:%s\n",(char*)unk_62E9);

    char unk_633A[128];
    sub_258C(unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4u, 1);
    printf("dword_62B4:%s\n",(char*)unk_633A);

    char unk_631C[128];
    unsigned char unk_44E4[10] = {0x23,0x18,0xCA,0x21,0x14,0xDF,0x1D,0x14,0x3C,0x00};
    unsigned char unk_44E0[4] = {0x37,0x3F,0x73,0x00};
    sub_258C(unk_631C, 9, unk_44E4, unk_44E0, 3u, 201);
    printf("dword_62B8:%s\n",(char*)unk_631C);

    char unk_632F[128];
    unsigned char unk_44D4[12] = {0xB1,0xB0,0x31,0xB4,0x32,0x33,0xB6,0xBA,0x39,0x34,0x80,0x00};
    sub_254C(unk_632F, 11, unk_44D4, unk_44FC, 0, 1);
    printf("dword_62BC:%s\n",(char*)unk_632F);

    char unk_6314[128];
    unsigned char unk_44B8[9] = {0xFD,0xFF,0xC1,0xDA,0x05,0xBD,0x1A,0x2C,0x00};
    sub_258C(unk_6314, 8, unk_44B8, ".6gq", 4u, 187);
    printf("dword_62C0:%s\n",(char*)unk_6314);

    return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if defined(__GNUC__)
typedef          long long ll;
typedef unsigned long long ull;
#define __int64 long long
#define __int32 int
#define __int16 short
#define __int8  char
#define MAKELL(num) num ## LL
#define FMT_64 "ll"
#elif defined(_MSC_VER)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "I64"
#elif defined (__BORLANDC__)
typedef          __int64 ll;
typedef unsigned __int64 ull;
#define MAKELL(num) num ## i64
#define FMT_64 "L"
#else
#error "unknown compiler"
#endif
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned long ulong;

typedef          char   int8;
typedef   signed char   sint8;
typedef unsigned char   uint8;
typedef          short  int16;
typedef   signed short  sint16;
typedef unsigned short  uint16;
typedef          int    int32;
typedef   signed int    sint32;
typedef unsigned int    uint32;
typedef ll              int64;
typedef ll              sint64;
typedef ull             uint64;

// Partially defined types:
#define _BYTE  uint8
#define _WORD  uint16
#define _DWORD uint32
#define _QWORD uint64
#if !defined(_MSC_VER)
#define _LONGLONG __int128
#endif

#ifndef _WINDOWS_
typedef int8 BYTE;
typedef int16 WORD;
typedef int32 DWORD;
typedef int32 LONG;
#endif
typedef int64 QWORD;
#ifndef __cplusplus
typedef int bool;       // we want to use bool in our C programs
#endif

// Some convenience macros to make partial accesses nicer
// first unsigned macros:
#define LOBYTE(x)   (*((_BYTE*)&(x)))   // low byte
#define LOWORD(x)   (*((_WORD*)&(x)))   // low word
#define LODWORD(x)  (*((_DWORD*)&(x)))  // low dword
#define HIBYTE(x)   (*((_BYTE*)&(x)+1))
#define HIWORD(x)   (*((_WORD*)&(x)+1))
#define HIDWORD(x)  (*((_DWORD*)&(x)+1))
#define BYTEn(x, n)   (*((_BYTE*)&(x)+n))
#define WORDn(x, n)   (*((_WORD*)&(x)+n))
#define BYTE1(x)   BYTEn(x,  1)         // byte 1 (counting from 0)
#define BYTE2(x)   BYTEn(x,  2)
#define BYTE3(x)   BYTEn(x,  3)
#define BYTE4(x)   BYTEn(x,  4)
#define BYTE5(x)   BYTEn(x,  5)
#define BYTE6(x)   BYTEn(x,  6)
#define BYTE7(x)   BYTEn(x,  7)
#define BYTE8(x)   BYTEn(x,  8)
#define BYTE9(x)   BYTEn(x,  9)
#define BYTE10(x)  BYTEn(x, 10)
#define BYTE11(x)  BYTEn(x, 11)
#define BYTE12(x)  BYTEn(x, 12)
#define BYTE13(x)  BYTEn(x, 13)
#define BYTE14(x)  BYTEn(x, 14)
#define BYTE15(x)  BYTEn(x, 15)
#define WORD1(x)   WORDn(x,  1)
#define WORD2(x)   WORDn(x,  2)         // third word of the object, unsigned
#define WORD3(x)   WORDn(x,  3)
#define WORD4(x)   WORDn(x,  4)
#define WORD5(x)   WORDn(x,  5)
#define WORD6(x)   WORDn(x,  6)
#define WORD7(x)   WORDn(x,  7)

// now signed macros (the same but with sign extension)
#define SLOBYTE(x)   (*((int8*)&(x)))
#define SLOWORD(x)   (*((int16*)&(x)))
#define SLODWORD(x)  (*((int32*)&(x)))
#define SHIBYTE(x)   (*((int8*)&(x)+1))
#define SHIWORD(x)   (*((int16*)&(x)+1))
#define SHIDWORD(x)  (*((int32*)&(x)+1))
#define SBYTEn(x, n)   (*((int8*)&(x)+n))
#define SWORDn(x, n)   (*((int16*)&(x)+n))
#define SBYTE1(x)   SBYTEn(x,  1)
#define SBYTE2(x)   SBYTEn(x,  2)
#define SBYTE3(x)   SBYTEn(x,  3)
#define SBYTE4(x)   SBYTEn(x,  4)
#define SBYTE5(x)   SBYTEn(x,  5)
#define SBYTE6(x)   SBYTEn(x,  6)
#define SBYTE7(x)   SBYTEn(x,  7)
#define SBYTE8(x)   SBYTEn(x,  8)
#define SBYTE9(x)   SBYTEn(x,  9)
#define SBYTE10(x)  SBYTEn(x, 10)
#define SBYTE11(x)  SBYTEn(x, 11)
#define SBYTE12(x)  SBYTEn(x, 12)
#define SBYTE13(x)  SBYTEn(x, 13)
#define SBYTE14(x)  SBYTEn(x, 14)
#define SBYTE15(x)  SBYTEn(x, 15)
#define SWORD1(x)   SWORDn(x,  1)
#define SWORD2(x)   SWORDn(x,  2)
#define SWORD3(x)   SWORDn(x,  3)
#define SWORD4(x)   SWORDn(x,  4)
#define SWORD5(x)   SWORDn(x,  5)
#define SWORD6(x)   SWORDn(x,  6)
#define SWORD7(x)   SWORDn(x,  7)


// Helper functions to represent some assembly instructions.

#ifdef __cplusplus

// Fill memory block with an integer value
inline void memset32(void *ptr, uint32 value, int count)
{
    uint32 *p = (uint32 *)ptr;
    for ( int i=0; i < count; i++ )
        *p++ = value;
}

// Generate a reference to pair of operands
template<class T>  int16 __PAIR__( int8  high, T low) { return ((( int16)high) << sizeof(high)*8) | uint8(low); }
template<class T>  int32 __PAIR__( int16 high, T low) { return ((( int32)high) << sizeof(high)*8) | uint16(low); }
template<class T>  int64 __PAIR__( int32 high, T low) { return ((( int64)high) << sizeof(high)*8) | uint32(low); }
template<class T> uint16 __PAIR__(uint8  high, T low) { return (((uint16)high) << sizeof(high)*8) | uint8(low); }
template<class T> uint32 __PAIR__(uint16 high, T low) { return (((uint32)high) << sizeof(high)*8) | uint16(low); }
template<class T> uint64 __PAIR__(uint32 high, T low) { return (((uint64)high) << sizeof(high)*8) | uint32(low); }

// rotate left
template<class T> T __ROL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T high = value >> (nbits - count);
    value <<= count;
    value |= high;
    return value;
}

// rotate right
template<class T> T __ROR__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    T low = value << (nbits - count);
    value >>= count;
    value |= low;
    return value;
}

// carry flag of left shift
template<class T> int8 __MKCSHL__(T value, uint count)
{
    const uint nbits = sizeof(T) * 8;
    count %= nbits;

    return (value >> (nbits-count)) & 1;
}

// carry flag of right shift
template<class T> int8 __MKCSHR__(T value, uint count)
{
    return (value >> (count-1)) & 1;
}

// sign flag
template<class T> int8 __SETS__(T x)
{
    if ( sizeof(T) == 1 )
        return int8(x) < 0;
    if ( sizeof(T) == 2 )
        return int16(x) < 0;
    if ( sizeof(T) == 4 )
        return int32(x) < 0;
    return int64(x) < 0;
}

// overflow flag of subtraction (x-y)
template<class T, class U> int8 __OFSUB__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return (sx ^ __SETS__(y)) & (sx ^ __SETS__(x2-y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return (sx ^ __SETS__(y2)) & (sx ^ __SETS__(x-y2));
    }
}

// overflow flag of addition (x+y)
template<class T, class U> int8 __OFADD__(T x, U y)
{
    if ( sizeof(T) < sizeof(U) )
    {
        U x2 = x;
        int8 sx = __SETS__(x2);
        return ((1 ^ sx) ^ __SETS__(y)) & (sx ^ __SETS__(x2+y));
    }
    else
    {
        T y2 = y;
        int8 sx = __SETS__(x);
        return ((1 ^ sx) ^ __SETS__(y2)) & (sx ^ __SETS__(x+y2));
    }
}

// carry flag of subtraction (x-y)
template<class T, class U> int8 __CFSUB__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) < uint8(y);
    if ( size == 2 )
        return uint16(x) < uint16(y);
    if ( size == 4 )
        return uint32(x) < uint32(y);
    return uint64(x) < uint64(y);
}

// carry flag of addition (x+y)
template<class T, class U> int8 __CFADD__(T x, U y)
{
    int size = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
    if ( size == 1 )
        return uint8(x) > uint8(x+y);
    if ( size == 2 )
        return uint16(x) > uint16(x+y);
    if ( size == 4 )
        return uint32(x) > uint32(x+y);
    return uint64(x) > uint64(x+y);
}

#else
// The following definition is not quite correct because it always returns
// uint64. The above C++ functions are good, though.
#define __PAIR__(high, low) (((uint64)(high)<<sizeof(high)*8) | low)
// For C, we just provide macros, they are not quite correct.
#define __ROL__(x, y) __rotl__(x, y)      // Rotate left
#define __ROR__(x, y) __rotr__(x, y)      // Rotate right
#define __CFSHL__(x, y) invalid_operation // Generate carry flag for (x<<y)
#define __CFSHR__(x, y) invalid_operation // Generate carry flag for (x>>y)
#define __CFADD__(x, y) invalid_operation // Generate carry flag for (x+y)
#define __CFSUB__(x, y) invalid_operation // Generate carry flag for (x-y)
#define __OFADD__(x, y) invalid_operation // Generate overflow flag for (x+y)
#define __OFSUB__(x, y) invalid_operation // Generate overflow flag for (x-y)
#endif

// No definition for rcl/rcr because the carry flag is unknown
#define __RCL__(x, y)    invalid_operation // Rotate left thru carry
#define __RCR__(x, y)    invalid_operation // Rotate right thru carry
#define __MKCRCL__(x, y) invalid_operation // Generate carry flag for a RCL
#define __MKCRCR__(x, y) invalid_operation // Generate carry flag for a RCR
#define __SETP__(x, y)   invalid_operation // Generate parity flag for (x-y)

// In the decompilation listing there are some objects declarared as _UNKNOWN
// because we could not determine their types. Since the C compiler does not
// accept void item declarations, we replace them by anything of our choice,
// for example a char:

#define _UNKNOWN char

#ifdef _MSC_VER
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif

int __fastcall sub_239C(_BYTE *a1, int a2, char *a3, int a4, unsigned int a5)
{
  _BYTE *v5; // r11
  char *v6; // r10
  int v7; // r5
  int v8; // r0
  unsigned int v9; // r7
  char v10; // r6
  int v11; // r8
  int result; // r0
  int v13; // r1
  char v14; // r1
  int v15; // r1
  int v16; // r0
  char v17; // r2
  char v18; // t1
  char v19[256]; // [sp+8h] [bp-128h]
  __int16 v20; // [sp+108h] [bp-28h]

  v5 = a1;
  v6 = a3;
  v7 = a2;
  v8 = 0;
  do
  {
    v19[v8] = v8;
    ++v8;
  }
  while ( v8 != 256 );
  v9 = 0;
  v10 = 0;
  v20 = 0;
  do
  {
    v11 = (unsigned __int8)v19[v9];
    result = *(unsigned __int8 *)(a4 + v9 % a5) + v11;
    v13 = (unsigned __int8)(result + v10);
    v19[v9] = v19[v13];
    v19[v13] = v11;
    ++v9;
    v10 += result;
  }
  while ( v9 != 256 );
  if ( v7 )
  {
    LOBYTE(result) = HIBYTE(v20);
    v14 = v20;
    do
    {
      LOBYTE(v15) = v14 + 1;
      --v7;
      LOBYTE(v20) = v15;
      v15 = (unsigned __int8)v15;
      LOBYTE(v16) = result + v19[(unsigned __int8)v15];
      HIBYTE(v20) = v16;
      v16 = (unsigned __int8)v16;
      v17 = v19[(unsigned __int8)v15];
      v19[v15] = v19[(unsigned __int8)v16];
      v19[v16] = v17;
      v14 = v20;
      result = HIBYTE(v20);
      v18 = *v6++;
      *v5++ = v19[(unsigned __int8)(v19[HIBYTE(v20)] + v19[(unsigned __int8)v20])] ^ v18;
    }
    while ( v7 );
  }
  return result;
}

int sub_258C(char* result, int a2, char* a3, char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*((unsigned char*)a4 + v7 % a5)) ^ (*((unsigned char*)a3 + v7) - a6);
            *(char *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}


char* sub_254C(char *result, int a2, unsigned char *a3, char* a4, int a5, char a6)
{
    unsigned int v6; // r3
    unsigned int v7; // t1

    if ( a2 )
    {
        v6 = a3[a2 - 1];
        do
        {
            v7 = *a3++;
            --a2;
            *result++ = ((char)v7 << a6) | (v6 >> (8 - a6));
            v6 = v7;
        }
        while ( a2 );
    }
    return result;
}

int sub_239C(char *a1, int a2, char *a3, char* a4, unsigned int a5)
{
    char *v5; // r11
    char *v6; // r10
    int v7; // r5
    int v8; // r0
    unsigned int v9; // r7
    int v10; // r6
    int v11; // r8
    int result; // r0
    int v13; // r1
    char v14; // r1
    int v15; // r1
    int v16; // r0
    char v17; // r2
    char v18; // t1
    char v19[256]; // [sp+8h] [bp-128h]
    short v20; // [sp+108h] [bp-28h]

    v5 = a1;
    v6 = a3;
    v7 = a2;
    v8 = 0;
    do
    {
        v19[v8] = v8;
        ++v8;
    }
    while ( v8 != 256 );
    v9 = 0;
    v10 = 0;
    v20 = 0;
    do
    {
        v11 = (unsigned char)v19[v9];
        result = *(unsigned char *)(a4 + v9 % a5) + v11;
        v13 = (unsigned char)(result + v10);
        v19[v9] = v19[v13];
        v19[v13] = v11;
        ++v9;
        v10 += result;
    }
    while ( v9 != 256 );
    if ( v7 )
    {
        LOBYTE(result) = HIBYTE(v20);
        v14 = v20;
        do
        {
            LOBYTE(v15) = v14 + 1;
            --v7;
            LOBYTE(v20) = v15;
            v15 = (unsigned char)v15;
            LOBYTE(v16) = result + v19[(unsigned char)v15];
            HIBYTE(v20) = v16;
            v16 = (unsigned char)v16;
            v17 = v19[(unsigned char)v15];
            v19[v15] = v19[(unsigned char)v16];
            v19[v16] = v17;
            v14 = v20;
            result = HIBYTE(v20);
            v18 = *v6++;
            *v5++ = v19[(unsigned char)(v19[HIBYTE(v20)] + v19[(unsigned char)v20])] ^ v18;
        }
        while ( v7 );
    }
    return result;
}

int sub_24F4(char* result, int a2, unsigned char* a3, unsigned char* a4, unsigned int a5, int a6)
{
    char* v6; // r7
    unsigned int v7; // r4

    v6 = result;
    if ( a2 )
    {
        v7 = 0;
        do
        {
            result = (*(unsigned char*)(a3 + v7) ^ a6) - *(unsigned char *)(a4 + v7 % a5);
            *(char* *)(v6 + v7++) = result;
        }
        while ( a2 != v7 );
    }
    return result;
}

int main()
{
    unsigned char unk_44FC[1] = {0x00};

    char unk_62D7[128] = {0};
    unsigned char unk_4509[7] = {0x58,0x71,0x10,0x7E,0x63,0x8D,0x00};
    sub_24F4(unk_62D7, 6, unk_4509, "9HbB", 4u, 197);
    printf("v0:%s\n",(char*)unk_62D7);

    char unk_62EF[128];
    unsigned char unk_448B[8] = {0x01,0x49,0x34,0x72,0x03,0x4E,0xB8,0x00};
    unsigned char unk_4488[3] = {0x6D,0x37,0x00};
    sub_24F4(unk_62EF, 7, unk_448B, unk_4488, 2u, 213);
    printf("dword_6294:%s\n",(char*)unk_62EF);

    char unk_630C[128] = {0};
    unsigned char unk_44F3[9] = {0xE6,0xCF,0xCF,0x89,0xBB,0x16,0x65,0x71,0x00};
    sub_239C(unk_630C, 8, unk_44F3, "LNAt", 4u);
    printf("dword_6298:%s\n",(char*)unk_630C);

    char unk_62DD[128] ={0};
    unsigned char unk_44AC[7] = {0x30,0xB4,0x7D,0x77,0x9C,0xA5,0x00};
    sub_239C(unk_62DD, 6, unk_44AC, "cOXt", 4u);
    printf("dword_629C:%s\n",(char*)unk_62DD);

    char unk_62E3[128];
    unsigned char unk_4481[7] = {0xA9,0xB5,0xB8,0xB7,0xC1,0x55,0x00};
    sub_24F4(unk_62E3, 6, unk_4481, "BMT", 3u, 1);
    printf("dword_62A0 :%s\n",(char*)unk_62E3);

    char unk_62F6[128] ={0};
    unsigned char unk_44C4[8] = {0x45,0xEB,0x5A,0x11,0x75,0x7E,0x4E,0x00};
    unsigned char unk_44C1[3] = {0x47,0x21,0x00};
    sub_239C(unk_62F6, 7, unk_44C4, unk_44C1,2u);
    printf("dword_62A4:%s\n",(char*)unk_62F6);

    char unk_62FD[128];
    unsigned char unk_44CC[8] = {0xB9,0xB9,0xB1,0x30,0x37,0x33,0x80,0x00};
    sub_254C(unk_62FD, 7, unk_44CC, unk_44FC, 0, 1);
    printf("dword_62A8:%s\n",(char*)unk_62FD);

    char unk_62CC[128];
    unsigned char unk_44A1[6] = {0xB5,0x34,0x36,0x36,0x80,0x00};
    sub_254C(unk_62CC, 5, unk_44A1, unk_44FC, 0, 1);
    printf("dword_62AC:%s\n",(char*)unk_62CC);

    unsigned char unk_44FD[7] = {0x39,0xB6,0xB2,0x32,0x38,0x80,0x00};
    char unk_62E9[128];
    sub_254C(unk_62E9, 6, unk_44FD, unk_44FC, 0, 1);
    printf("dword_62B0:%s\n",(char*)unk_62E9);

    char unk_633A[128];
    sub_258C(unk_633A, 15, "3:*8(-&\x1B\"@%%7)B", "BMAE", 4u, 1);
    printf("dword_62B4:%s\n",(char*)unk_633A);

    char unk_631C[128];
    unsigned char unk_44E4[10] = {0x23,0x18,0xCA,0x21,0x14,0xDF,0x1D,0x14,0x3C,0x00};
    unsigned char unk_44E0[4] = {0x37,0x3F,0x73,0x00};
    sub_258C(unk_631C, 9, unk_44E4, unk_44E0, 3u, 201);
    printf("dword_62B8:%s\n",(char*)unk_631C);

    char unk_632F[128];
    unsigned char unk_44D4[12] = {0xB1,0xB0,0x31,0xB4,0x32,0x33,0xB6,0xBA,0x39,0x34,0x80,0x00};
    sub_254C(unk_632F, 11, unk_44D4, unk_44FC, 0, 1);
    printf("dword_62BC:%s\n",(char*)unk_632F);

    char unk_6314[128];
    unsigned char unk_44B8[9] = {0xFD,0xFF,0xC1,0xDA,0x05,0xBD,0x1A,0x2C,0x00};
    sub_258C(unk_6314, 8, unk_44B8, ".6gq", 4u, 187);
    printf("dword_62C0:%s\n",(char*)unk_6314);

    return 0;
}
代码运行如下:

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-4-7 23:01 被wx_A.R编辑 ,原因: 解密小程序的修改,以便能够正确解密那三个先前未解密的程序;增加了IDA伪代码通用宏的声明;
上传的附件:
收藏
免费 5
支持
分享
最新回复 (12)
雪    币: 12502
活跃值: (3053)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
这个帖子才是值得精华的东西。
2020-4-3 08:05
0
雪    币: 1365
活跃值: (3579)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
66
2020-4-3 10:17
0
雪    币: 6573
活跃值: (3893)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
4
不错啊,这才是真正能力的体现,分析思路一目了然
2020-4-4 07:28
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
希望上传一下apk样本撒
2020-4-4 16:46
0
雪    币: 365
活跃值: (559)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
LowRebSwrd 不错啊,这才是真正能力的体现,分析思路一目了然
谢版主加优
2020-4-4 20:12
0
雪    币: 365
活跃值: (559)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
sayaeffify 希望上传一下apk样本撒
样本已经上传
2020-4-4 20:12
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
666
2020-4-7 17:13
0
雪    币: 158
活跃值: (755)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
这个app被一堆人写成过帖子
2020-4-7 18:39
0
雪    币: 365
活跃值: (559)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
Mars. 这个app被一堆人写成过帖子[em_10]
样本摆在那里,至少这个是我自己的思路,没有“天下文章一大抄”,如果我跟他们思路一样或者我抄袭他们的思路我是没脸记这些流水账的,还是一个,思路。
2020-4-7 18:46
0
雪    币: 365
活跃值: (559)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
11
先前漏掉的解密函数已经更新,解密小程序里面增加了IDA C伪代码的通用宏定义和类型定义,在以后分析C伪代码的时候这部分可以直接拿来套用。
2020-4-7 23:04
0
雪    币: 582
活跃值: (317)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
厉害 喜欢这样的帖子
2020-4-8 08:07
0
雪    币: 619
活跃值: (361)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
果然开发是逆向之基本
2020-5-12 09:13
0
游客
登录 | 注册 方可回帖
返回
//