一道CrackMe的分析
本帖最后由 Enigma_G 于 2017-4-27 12:41 编辑0x00 闲言碎语
之前自己写的分析文章,分析的时候也遇到了一点问题,然后参考了一些文章得以解决。如有错误,请指出:Dweeqw
----------
0x01 APK获取
apk下载地址
http://gslab.qq.com/competition/firstTurn.shtml
----------
0x02 java层分析
package com.tencent.tencent2016a;
import android.app.AlertDialog$Builder;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.a.f;
import android.widget.Button;
import android.widget.EditText;
import com.a.a.e.a.a;
import com.a.a.e.a.b;
public class MainActivity extends f {
Button o;
Button p;
EditText editText;
EditText editText2;
AlertDialog$Builder s;
static {
System.loadLibrary("CheckRegister");//加载类库
}
public MainActivity() {
super();
this.o = null;
this.p = null;
this.editText = null;
this.editText2 = null;
this.s = null;
}
public native int NativeCheckRegister(String arg1, String arg2) {
}
protected void onActivityResult(int requestCode, int resultCode, Intent arg6) {
b v0 = a.a(requestCode, resultCode, arg6);
if(v0 == null) {
super.onActivityResult(requestCode, resultCode, arg6);
}
else if(v0.a() != null) {
String[] v0_1 = v0.a().split(":");
this.editText.setText(v0_1);
this.editText2.setText(v0_1);
}
}
protected void onCreate(Bundle arg4) {
super.onCreate(arg4);
this.setContentView(2130968601);
this.editText = this.findViewById(2131558472);
this.editText2 = this.findViewById(2131558473);
this.o = this.findViewById(2131558474);// button
this.s = new AlertDialog$Builder(((Context)this)); //新建一个对话框
this.p = this.findViewById(2131558475);// btnScan
this.s.setMessage("Check Result"); //对话框设置信息
this.s.setTitle("Check Result"); //对话框设置标题
this.s.setPositiveButton("OK", new com.tencent.tencent2016a.a(this)); //对话框设置按钮和点击事件
if(this.p != null) {
this.p.setOnClickListener(new com.tencent.tencent2016a.b(this));
}
if(this.o != null) {
this.o.setOnClickListener(new c(this));//关键事件
}
}
}
分析完后,跟进c类进行查看:
package com.tencent.tencent2016a;
import android.view.View$OnClickListener;
import android.view.View;
class c implements View$OnClickListener {
c(MainActivity arg1) {
this.a = arg1;
super();
}
public void onClick(View arg5) {
String v0 = this.a.editText.getText().toString();// Name
String v1 = this.a.editText2.getText().toString();// Passwd
if(v0.length() < 6 || v0.length() > 20) { //Name在6-20之间
this.a.s.setMessage("Name too short(<6) or too long(>20)!");
}
else if(1 == this.a.NativeCheckRegister(v0, v1)) {
this.a.s.setMessage("Check Success!");
}
else {
this.a.s.setMessage("Check Fail!");
}
this.a.s.create().show();
}
}
那么思路很明确了,要下面条件成立:
1 == this.a.NativeCheckRegister(v0, v1))
----------------------
0x03 so文件分析
用IDA打开so文件:
F5大法好
int __fastcall Java_com_tencent_tencent2016a_MainActivity_NativeCheckRegister(int a1, int a2, int a3, int a4)
{
int v4; // r7@1
int v5; // r5@1
int v6; // r4@1
int v7; // r6@1
int v8; // ST00_4@1
int v9; // ST04_4@1
v4 = a3;
v5 = a4;
v6 = a1;
v7 = (*(int (__cdecl **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0);
v8 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v6 + 676))(v6, v5, 0);
v9 = sub_1634(v7, v8);
(*(void (__fastcall **)(int, int, int))(*(_DWORD *)v6 + 680))(v6, v4, v7);
(*(void (__fastcall **)(int, int, int))(*(_DWORD *)v6 + 680))(v6, v5, v8);
return v9;
}
手动修复一下参数和方法和变量名,如下:
int __fastcall Java_com_tencent_tencent2016a_MainActivity_NativeCheckRegister(JNIEnv *a1, jclass a2, jstring Name, jstring Passwd)
{
jstring v4; // r7@1
jstring v5; // r5@1
JNIEnv *v6; // r4@1
const char *Name_I; // r6@1
const char *Pass_I; // ST00_4@1
int v9; // ST04_4@1
v4 = Name;
v5 = Passwd;
v6 = a1;
Name_I = (*a1)->GetStringUTFChars(a1, Name, 0);
Pass_I = (*v6)->GetStringUTFChars(v6, v5, 0);
v9 = sub_1634(Name_I, (int)Pass_I);
(*v6)->ReleaseStringUTFChars(v6, v4, Name_I);
(*v6)->ReleaseStringUTFChars(v6, v5, Pass_I);
return v9;// 要让v9==1
}
那么,继续跟进sub_1634方法,这里一段一段来分析:
int __fastcall sub_1634(const char *a1, int a2)//这里参数识别应该是char*a2
{
int v2; // r6@1
signed int v3; // r5@1
int result; // r0@2
signed int v5; // r4@3
char *v6; // r7@4
int v7; // r3@4
int v8; // r4@6
int v9; // r4@7
int v10; // r1@8
const char *v11; // @1
int v12; // @7
char v13; // @7
char s; // @3
char v15; // @5
int v16; // @1
v2 = a2;
v11 = a1;
v16 = _stack_chk_guard; //这是一种栈平衡的验证,因为如果栈不平衡,程序会发生异常
v3 = j_j_strlen(a1);
if ( (unsigned int)(v3 - 6) > 0xE )
goto LABEL_18;
j_j_memset(s, 0, 0x14u); //进行s数组的初始化
v5 = 0;
do
{
v6 = &s;
v7 = v11 * (v5 + 20160126) * v3;
++v5;
*(_DWORD *)v6 += v7;
}
while ( v5 != 16 );
稍作优化后,便于分析:
int __fastcall sub_1634(const char *Name, char *Passwd)
{
char *EPass; // r6@1
signed int v3; // r5@1
int result; // r0@2
signed int j; // r4@3
char *ps; // r7@4
int v7; // r3@4
int v8; // r4@6
int i; // r4@7
int Vpass; // r1@8
const char *Ename; // @1
int FinName; // @7
int FinPass; // @7
char Vname; // @3
char passEncode; // @5
int v16; // @1
EPass = Passwd;
Ename = Name;
v16 = _stack_chk_guard;
v3 = j_j_strlen(Name);
if ( (unsigned int)(v3 - 6) > 0xE ) // 名字长度在6-20之间
goto LABEL_18;
j_j_memset(Vname, 0, 0x14u);// 初始化
j = 0;
do
{
ps = &Vname; // 取址
v7 = Ename * (j + 20160126) * v3;
++j;
*(_DWORD *)ps += v7;
}
while ( j != 16 );
那么下面直接贴出全部修改后的:
int __fastcall sub_1634(const char *Name, char *Passwd)
{
char *EPass; // r6@1
signed int v3; // r5@1
int result; // r0@2
signed int j; // r4@3
char *ps; // r7@4
int v7; // r3@4
int v8; // r4@6
int i; // r4@7
int Vpass; // r1@8
const char *Ename; // @1
int FinName; // @7
int FinPass; // @7
char Vname; // @3
char passEncode; // @5
int v16; // @1
EPass = Passwd;
Ename = Name;
v16 = _stack_chk_guard;
v3 = j_j_strlen(Name);
if ( (unsigned int)(v3 - 6) > 0xE ) // 名字长度在6-20之间
goto LABEL_18;
j_j_memset(Vname, 0, 0x14u);// 初始化
j = 0;
do
{
ps = &Vname; // 取址
v7 = Ename * (j + 20160126) * v3;
++j;
*(_DWORD *)ps += v7;
}
while ( j != 16 );// 对Ename进行一种转换
j_j_memset(passEncode, 0, 0x400u);// 初始化
if ( EncodePass1((int)EPass) > 1024 || (v8 = EncodePass2((int)passEncode, (int)EPass), v8 != 20) )
{
LABEL_18: // if不满足
result = 0;
}
else// 继续
{
j_j_memset(FinName, 0, 0x14u);// 初始化
j_j_memset(FinPass, 0, 0x14u);// 初始化
i = 0;
do
{
Vpass = *(_DWORD *)&passEncode;
FinName = *(_DWORD *)&Vname / 10;
FinPass = Vpass;
++i;
}
while ( i != 5 );
result = 0;
if ( FinPass + FinName == FinPass
&& FinPass + FinName + FinName == 2 * FinPass
&& FinName + FinPass == FinPass
&& FinName + FinPass + FinName == 2 * FinPass )
{
result = (unsigned int)(FinName + FinPass - 3 * FinName) <= 0;// 要让result ==1
}
}
if ( v16 != _stack_chk_guard )// 栈不平衡
j_j___stack_chk_fail(result);
return result;
}
这里有一个地方需要注意,那就是IDA的参数识别问题:
这里分析下v13,他的每一个元素都是通过v10进行传递,总共传递了5次,也就是说,v13其实大小只有5,那么这里识别的v13其实相对应的是v13,那么我们修改下v13的大小,方便审读
那么双击v13,
将它改为和上面一样,右键set type(或者快捷键Y)
改为int类型数组5个长度即可:
修复完后
然后还有就是一些参数类型识别的问题,char识别为int,int识别为char,分析一下修改就好了
从刚刚给出的修改后的代码可以分析:
我们要求Passwd,首先根据这个求出FinPass:
if ( FinPass + FinName == FinPass
&& FinPass + FinName + FinName == 2 * FinPass
&& FinName + FinPass == FinPass
&& FinName + FinPass + FinName == 2 * FinPass )
然后根据FinPass求出passEncode
Vpass = *(_DWORD *)&passEncode;
FinName = *(_DWORD *)&Vname / 10;
FinPass = Vpass;
++i;
最后,根据这个函数,求出我们输入的EPass
跟进分析:
int __fastcall EncodePass2(char *passEncode, char *EPass)
{
char *v2; // r3@1
int v3; // r3@3
int v4; // r2@3
int v5; // r5@3
char *v6; // r3@4
int v7; // r3@5
int v8; // r6@5
v2 = EPass;
do
++v2;
while ( (unsigned __int8)a456789[(unsigned __int8)*(v2 - 1)] <= 0x3Fu );// a456789 == "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>@@@?456789:;<=@@@@@@
v3 = v2 - EPass;
v4 = v3 - 1;
v5 = 3 * ((v3 + 2) / 4);
while ( 1 )
{
v6 = passEncode;
if ( v4 <= 4 )
break;
v4 -= 4;
*passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 4) | 4 * a456789[(unsigned __int8)*EPass];
passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 2) | 16 * a456789[(unsigned __int8)EPass];
v7 = (unsigned __int8)EPass;
v8 = (unsigned __int8)EPass;
EPass += 4;
passEncode = (a456789 << 6) | a456789;
passEncode += 3;
}
if ( v4 > 1 )
{
*passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 4) | 4 * a456789[(unsigned __int8)*EPass];
if ( v4 == 2 )
{
v6 = passEncode + 1;
}
else
{
passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 2) | 16
* a456789[(unsigned __int8)EPass];
if ( v4 == 4 )
{
v6 = passEncode + 3;
passEncode = (a456789[(unsigned __int8)EPass] << 6) | a456789[(unsigned __int8)EPass];
}
else
{
v6 = passEncode + 2;
}
}
}
*v6 = 0;
return v5 - (-v4 & 3);
}
然后分析一下,其实发现就是一张编码表索引
这个其实就是编码表的起始位置,双击进去查看
然后在Hex窗口查看
用WinHex打开:
右键->Edit->Copy block->C source
然后根据条件"<=0x3f"
,写一个c脚本:
// keygen.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
using namespace std;
unsigned table[] = {
0x3E, 0x40, 0x40, 0x40, 0x3F, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41,
0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x00,
0x00, 0x00, 0x00, 0x00
};
int main()
{
unsigned a;
for (int i = 0; i <= 0xff; i++) {
a = table;
if (a <= 0x3f) {
cout << "input" << hex << i << " ,value:" << a << endl;
}
}
system("pause");
return 0;
}
编码表的对应关系:
0x04 Base64算法
这里谈谈Base64加密,其实也算不上加密,应该说是一种编码转换,然后在一张表上进行索引,百度一下会有很多介绍的文章,这里就大概提一下转换的步骤
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。
举个简单的例子,我要对mask这个字符串进行base64编码转换,那么请看下面步骤:
1.将 'mask' 这个字符串进行二进制编码转换
m->01101101
a ->01100001
s ->01110011
k ->01101011
2.进行base64分组,将这四个合并一起,每6位一组
(00)011011(00)010110(00)000101(00)110011 (00)011010 (00)110000(不足6位,用0补) 0000000 00000000 (补全)
3.转换为10进制
00011011 -> 27
00010110 -> 22
00000101 -> 5
00110011 ->51
00011010 ->26
00110000 ->48
4.参照编码表
bWFzaw==(最后两个‘=’是补全的)
0x05 算法分析
本题算法和Base64相似,都是转换后码表索引
*passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 4) | 4 * a456789[(unsigned __int8)*EPass];
passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 2) | 16 * a456789[(unsigned __int8)EPass];
v7 = (unsigned __int8)EPass;
v8 = (unsigned __int8)EPass;
EPass += 4;
passEncode = (a456789 << 6) | a456789;
passEncode += 3;
}
if ( v4 > 1 )
{
*passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 4) | 4 * a456789[(unsigned __int8)*EPass];
if ( v4 == 2 )
{
v6 = passEncode + 1;
}
else
{
passEncode = ((unsigned __int8)a456789[(unsigned __int8)EPass] >> 2) | 16
* a456789[(unsigned __int8)EPass];
if ( v4 == 4 )
{
v6 = passEncode + 3;
passEncode = (a456789[(unsigned __int8)EPass] << 6) | a456789[(unsigned __int8)EPass];
}
else
{
v6 = passEncode + 2;
}
}
}
思路:
name -> Vname->FinName
pass -> passEncode -> Vpass -> FinPass
FinName和FinPass之间的关系,通过这个算出FinPass,然后再根据算法,推出pass
FinPass + FinName == FinPass&& FinPass + FinName + FinName == 2 * FinPass&& FinName + FinPass == FinPass&& FinName + FinPass + FinName == 2 * FinPass
然后注册机我参考的是看雪的一个分享,自己写的时候思路出了点问题{:1_924:},就拿了别人的过来分析
package com.cx.tencent20161.utils;
/**
* Created by cx on 16/3/9.
*/
public class KeyGen {
private byte[] name = null;
private String code = null;
private int[] nameCrypt = null;
private int[] nameCrypt2 = null;
private int[] codeCrypt = null;
private byte[] codeCrypt2 = null;
private byte[] resByte = null;
private byte[] table = {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x3E,0x40,0x40,0x40,0x3F,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x40,0x40,0x40,0x40,0x40,0x40,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
public KeyGen(String n) throws Exception{
this.name = n.getBytes();
if (this.name.length < 6 || this.name.length > 20) {
throw new Exception();
}
nameCrypt = new int;
nameCrypt2 = new int;
codeCrypt = new int;
resByte = new byte;
codeCrypt2 = new byte;
}
public void nameProc() {
int tmp = 0;
int i = 0, j = 0;
for (; i < 16; i++, j = i % name.length) {
nameCrypt = ((name * (0x1339e7e + i) * name.length) + tmp) & 0x0ff;
tmp = (((name * (0x1339e7e + i) * name.length) + tmp) >> 0x8) & 0x00ffffff;
}
nameCrypt = tmp & 0x0ff;
nameCrypt = (tmp & 0x0ff00) >> 8;
nameCrypt = (tmp & 0x0ff0000) >> 16;
for (i = 0; i < 5; i++) {
nameCrypt2 = nameCrypt;
nameCrypt2 = nameCrypt2 << 8 | nameCrypt;
nameCrypt2 = nameCrypt2 << 8 | nameCrypt;
nameCrypt2 = nameCrypt2 << 8 | nameCrypt;
}
for (i = 0; i < 5; i++) {
nameCrypt2 = nameCrypt2 / 10;
}
}
public String getCode() {
StringBuilder sb = new StringBuilder();
codeCrypt = nameCrypt2 + nameCrypt2;
codeCrypt = codeCrypt + nameCrypt2;
codeCrypt = 3 * nameCrypt2 - nameCrypt2;
codeCrypt = nameCrypt2 + nameCrypt2;
codeCrypt = codeCrypt + nameCrypt2;
for (int i = 0; i < 5; i++) {
codeCrypt2 = (byte) (codeCrypt & 0x0ff);
codeCrypt2 = (byte) ((codeCrypt >> 8) & 0x0ff);
codeCrypt2 = (byte) ((codeCrypt >> 16) & 0x0ff);
codeCrypt2 = (byte) ((codeCrypt >> 24) & 0x0ff);
}
for (int i = 0; i <= 6; i++) {
byte tmp = 0;
if (i == 6) {
tmp = (byte) ((codeCrypt2 & 0x0ff) >> 2);
sb.append((char) lookupTableRev(tmp));
tmp = (byte) (((codeCrypt2 & 0x03) << 4) | ((codeCrypt2 >> 4)) & 0x0f);
sb.append((char) lookupTableRev(tmp));
tmp = (byte) (((codeCrypt2 & 0xf) << 2) | ((codeCrypt2 & 0x0ff) >> 6));
sb.append((char) lookupTableRev(tmp));
} else {
tmp = (byte) ((codeCrypt2 & 0x0ff) >> 2);
sb.append((char) lookupTableRev(tmp));
tmp = (byte) (((codeCrypt2 & 0x03) << 4) | ((codeCrypt2 >> 4)) & 0x0f);
sb.append((char) lookupTableRev(tmp));
tmp = (byte) (((codeCrypt2 & 0xf) << 2) | ((codeCrypt2 & 0x0ff) >> 6));
sb.append((char) lookupTableRev(tmp));
tmp = (byte) (codeCrypt2 & 0x3f);
sb.append((char) lookupTableRev(tmp));
}
}
return sb.toString();
}
private int lookupTableRev(byte content) {
for (int i = 0; i < 256; i++) {
if (table == content) {
return i;
} else {
continue;
}
}
return -1;
}
}
附上原文链接
http://bbs.pediy.com/thread-208933.htm
这篇文章是直接分析的arm汇编的
-------------
0x06 总结
主要学习到了IDA修复参数的一些小技巧,以及一些算法的分析。都是新手路上的总结而已,师傅们不要见笑:Dweeqw
apk以及注册机打包好了
http://pan.baidu.com/s/1dFgRNZb
挥汗如雨 发表于 2017-4-27 13:09
怎么手动修改变量名啊,楼主能不能详细说一下
IDA里修改变量名吗?可以快捷键N或者你在变量上右键,然后rename v10 = (JNIEnv *)j_j_strlen(v7);
JNIEnv *v10;
请问下楼主,我修复变量还是有这些JNIEnv*存在 ,求教如何修复这些? 本帖最后由 Enigma_G 于 2017-4-27 12:42 编辑
:lol自己占沙发 感谢楼主 Oo不弃 发表于 2017-4-27 12:47
感谢楼主
共同进步::lol 怎么手动修改变量名啊,楼主能不能详细说一下 Enigma_G 发表于 2017-4-27 13:17
IDA里修改变量名吗?可以快捷键N或者你在变量上右键,然后rename
好的,谢谢 感谢分享... 我就说啊,公司天天说招不到逆向,这里不是一堆逆向的吗? 谢谢分享