Python Anti anti-crawl - 5oqW6Z+z V1 getName(0x2)

說在前面的話

原本想只看彙編來一行行的分析的,其實我還學了近半個月的彙編。。。不過看到這個算法的彙編代碼我第一個想法就是放棄,下次吧,(: 說實話這個getName很簡單,原本想從彙編開始分析的。。。但我看到那個排序算法我就頭大,此次就放棄吧javascript


正文

先來僞代碼java

char *__fastcall getName(int v25_serverTime, char *params, char *a3) {
  char *v3; // r4
  char *v4; // ST14_4
  char v9; // [sp+18h] [bp-10h]

  std::unique_lock<std::mutex>::unique_lock(&v9, &mtx);
  if ( (unsigned __int8)inited ^ 1 )
  {
    as[0] = 0;
    std::unique_lock<std::mutex>::unlock(&v9);
    v3 = as;
  }
  else
  {
    if ( v25_serverTime < 0 )
      v25_serverTime = time(0);
    if ( params && a3 )
    {
      memset(&concat_buffer, 0, 4097u);         // 將concat_buffer地址後面4097個字節所有用0填充。。恰好填滿
      snprintf((char *)&concat_buffer, 4096u, "%s", params);// 格式化字符串;將params所有放入concat_buffer,由於concat_buffer長度遠大於params,因此後面會自動加結束符'\0'
      v4 = getName(v25_serverTime, (char *)&concat_buffer);
      std::unique_lock<std::mutex>::unlock(&v9);
      v3 = v4;
    }
    else
    {
      as[0] = 0;
      std::unique_lock<std::mutex>::unlock(&v9);
      v3 = as;
    }
  }
  std::unique_lock<std::mutex>::~unique_lock(&v9);
  return v3;
複製代碼

第一個參數時間戳 第二參數是拼接後的url參數中的value,不過這裏的這個value有點不一樣,它拼接的時候排序過,順序就是按照參數key的順序(a-z)排序的,用python sorted就知道了 第三個參數是個空參數 返回結果就是咱們要的東西了 參數結果hook代碼以下python

String.prototype.format = function () {
    var values = arguments;
    return this.replace(/\{(\d+)\}/g, function (match, index) {
        if (values.length > index) {
            return values[index];
        } else {
            return "";
        }
    });
}
// Memory.readUtf8String
var mru8s = function(addr) {return Memory.readUtf8String(addr)}
// Memory.readPointer
var mrp = function(addr) {return Memory.readPointer(addr)}
// Memory.allocUtf8String
var mau8s = function(addr) {return Memory.allocUtf8String(addr)}


var JNI_OnLoad;
var exports = Module.enumerateExportsSync("libuserinfo.so");
for (var i = 0; i < exports.length; i++) {
    var name = exports[i].name;
    var addr = exports[i].address;
    if (name == 'JNI_OnLoad') {
        JNI_OnLoad = addr;
    }
}

var BASE_ADDR = parseInt(JNI_OnLoad) - parseInt("0x14504");
var addr = '0x' + parseInt(BASE_ADDR + parseInt('0x11828')).toString(16);

var i = 0;
Interceptor.attach(new NativePointer(addr), {
    onEnter: function(args) {
        i++;
        var msg = '===============' + i + '===============\n' +
                    '參數1 > {0}\n參數2 > {1}\n參數3 > {2}\n'
                    .format(args[0], mru8s(args[1]), mru8s(args[2]));
        console.log(msg);
    },
    onLeave: function(retval) {
        console.log('retval > ', mru8s(retval));
    }
});
複製代碼

輸出android

[*] Running CTF
===============1===============
參數1 > 0x5dc91e39
參數2 > 1573461562225wifi1128awemewandoujia200Xiaomi69143529399androidMIa8aUD44088263783316zh166ffa82bd3b11065942891080*2029no_retryefc84c17a157346156116628686950355594321661.6.6
參數3 > 

retval >  a13541cc39834d8e691b33d3509c9dcae1e1
複製代碼

從這個getName僞代碼中能夠看到又調用了一個名爲getName的方法,其僞代碼以及不知道我什麼是時候寫的註釋以下c++

// 這個方法應該是個加密方法
char *__fastcall getName(int serverTime, char *params) {
  signed int i; // [sp+Ch] [bp-1Ch]
  signed int j; // [sp+10h] [bp-18h]
  signed int k; // [sp+14h] [bp-14h]
  signed int l; // [sp+18h] [bp-10h]

  if ( (unsigned __int8)inited ^ 1 )
  {
    as[0] = 0;
  }
  else if ( params )
  {
    sprintf(shuffle1, "%08x", serverTime);      // 格式化字符串,將時間戳轉爲16進制
    sprintf(shuffle2, "%08x", serverTime);      // 同上
    shuffle((int)shuffle1, (char *)&array1);    // 這個是將shuffle1隨機排序,array1=57218436
    shuffle((int)shuffle2, (char *)&array2);    // 同上,array2=15387264
    getMd5(params);                             // 這裏將url參數進行md5加密,加密的結果是md5_value
    if ( serverTime & 1 )                       // 這裏是判斷時間戳是否是2的倍數
      getMd5(md5_value);                        // 是的話就再加密一次
    as[0] = 97;                                 // 先將as數組第一位添加字符a
    byte_612C5 = version;                       // 這裏實際是as[1] = version;version=1
    for ( i = 0; i <= 7; ++i )                  // 接着循環7次,將md5加密後的params的前7個字符添加到as字符數組,as中存放不是依次存放,以2*(i+1)索引存放
      as[2 * (i + 1)] = md5_value[i];
    for ( j = 0; j <= 7; ++j )                  // 將第二次隨機排序後的時間戳前7位取出,以(2*j+3)索引存放到as字符數組中
      as[2 * j + 3] = shuffle2[j];
    byte_612D6 = 0;
    for ( k = 0; k <= 7; ++k )                  // 將第一次隨機排序後的時間戳前7位取出,以(2*k)索引存放到cp字符數組中
      cp[2 * k] = shuffle1[k];
    for ( l = 0; l <= 7; ++l )                  // 將md5加密後的params按索引l+24取出,以(2*l+1)索引存放到cp字符數組
      cp[2 * l + 1] = md5_value[l + 24];
    byte_6139C = 101;                           // cp[16] = 0x65;0x65十進制101,在ascii中是字符e
    byte_6139D = version;                       // cp[17] = version;version=1
    byte_6139E = 0;                             // cp[18] = 0
    strncpy(&byte_612D6, cp, 0x12u);            // 將字符數組cp的前18位也就是複製到byte_612D6所在的地址
  }
  else
  {
    as[0] = 0;
  }
  return as;
}
複製代碼

這裏咱們只須要看那個排序方法shuffle算法

// 字符串隨機排序
int __fastcall shuffle(int result, char *a2) {
  byte_60123 = *(_BYTE *)(result + 7);
  byte_6011E = *(_BYTE *)(result + 2);
  byte_60120 = *(_BYTE *)(result + 4);
  byte_60122 = *(_BYTE *)(result + 6);
  byte_6011F = *(_BYTE *)(result + 3);
  byte_60121 = *(_BYTE *)(result + 5);
  byte_6011D = *(_BYTE *)(result + 1);
  tmp[0] = *(_BYTE *)result;
  *(_BYTE *)result = tmp[(unsigned __int8)*a2 - 49];
  *(_BYTE *)(result + 2) = tmp[(unsigned __int8)a2[2] - 49];
  *(_BYTE *)(result + 4) = tmp[(unsigned __int8)a2[4] - 49];
  *(_BYTE *)(result + 6) = tmp[(unsigned __int8)a2[6] - 49];
  *(_BYTE *)(result + 5) = tmp[(unsigned __int8)a2[5] - 49];
  *(_BYTE *)(result + 3) = tmp[(unsigned __int8)a2[3] - 49];
  *(_BYTE *)(result + 1) = tmp[(unsigned __int8)a2[1] - 49];
  *(_BYTE *)(result + 7) = tmp[(unsigned __int8)a2[7] - 49];
  *(_BYTE *)(result + 8) = 0;                   // 這裏不是數字0,這是結束符號\0
  return result;
}
複製代碼

排序方法對應python代碼數組

def shuffle(result, array):
    ret = ['0', '0', '0', '0', '0', '0', '0', '0']
    ret[2] = result[ord(array[2]) - 49]
    ret[4] = result[ord(array[4]) - 49]
    ret[6] = result[ord(array[6]) - 49]
    ret[5] = result[ord(array[5]) - 49]
    ret[3] = result[ord(array[3]) - 49]
    ret[1] = result[ord(array[1]) - 49]
    ret[7] = result[ord(array[7]) - 49]
    ret[0] = result[ord(array[0]) - 49]
    return ''.join(ret)
複製代碼

getName對應python代碼bash

def get_name(server_time, params):
    _as = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
    _cp = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
    shuffle1 = hex(server_time)[2:]
    shuffle2 = hex(server_time)[2:]
    shuffle1 = shuffle(shuffle1, '57218436')
    shuffle2 = shuffle(shuffle2, '15387264')
    params_md5 = hashlib.md5(params.encode('utf-8')).hexdigest()
    if server_time & 1:
        params_md5 = hashlib.md5(params_md5.encode('utf-8')).hexdigest()
    _as[0] = chr(97)
    _as[1] = chr(49)
    for i in range(8):
        _as[2*(i+1)] = params_md5[i]

    for j in range(8):
        _as[2*j+3] = shuffle2[j]

    for k in range(8):
        _cp[2*k] = shuffle1[k]

    for l in range(8):
        _cp[2*l+1] = params_md5[l+24]
    
    _cp[16] = chr(101)
    _cp[17] = chr(49)

    return ''.join(_as + _cp)
複製代碼

我已經測試了不少次了,和hook到的結果一毛同樣,固然不信的話能夠用上面hook到的結果測試測試


最後

emmm,這個最後獲取結果好像就這些了吧(好敷衍呀),等我啥時候想起來要補充的再添加吧,太餓了。。。。ui

相關文章
相關標籤/搜索