Android破解实战:游戏蜂窝3.19版本破解记录
下载ApkTool
ApkTool下载地址:
https://ibotpeaches.github.io/Apktool/
ApkTool安装说明:
https://ibotpeaches.github.io/Apktool/install/
运行apktool d target.apk反编译资源
运行apktool byouxifengwo -o ReYXFW.apk 重打包APK
uiautomatorviewer在sdk的tool目录下
生成签名密钥
唤出CMD:开始—运行—输入CMD后,点确定或按ENTER回车键。
唤出CMD后输入下面命令后按回车键:
cd /d C:\Program Files\Java\jdk1.7.0\bin
输入后按回车再输入下面命令后按回车
keytool -genkey -alias abc.keystore-keyalg RSA -validity 20000 -keystore abc.keystore
abc可改为其他名称,命令区分大小写。
执行命令后会出现下面步骤:
输入keystore密码:[密码不显示,输入密码按回车即可开
再次输入新密码:[密码不显示,输入密码按回车即可开
您的名字与姓氏是什么?
[Unknown]: tttabc
您的组织单位名称是什么?
[Unknown]: www.tttabc.com
您的组织名称是什么?
[Unknown]: www.tttabc.com
您的组织名称是什么?
[Unknown]: www.tttabc.com
您所在的城市或区域名称是什么?
[Unknown]: NewYork
您所在的州或省份名称是什么?
[Unknown]: NewYork
该单位的两字母国家代码是什么
[Unknown]: CN
CN=abc,OU=www.tttabc.com,O=www.tttabc.com,L=New York,ST
=New York, C=CN 正确吗?
[否]: Y
输入<abc.keystore>的主密码
(如果和 keystore 密码相同,按回车):
成功后将会在C:\Program Files\Java\jdk1.7.0\bin 下产生一个名为abc.keystore的文件。
其中参数-validity为证书有效天数,这里我们写的大些——20000天。在输入密码时没有回显,只管输入就可以了,一般位数建议使用20位,需要记下来后面还要用。
接下来我们开始为apk文件签名了。
签名apk文件
将要签名的APK放到C:\Program Files\Java\jdk1.7.0\bin 下,apk最好命名为简单的名字,如123.apk。
唤出CMD: 开始—运行—输入CMD后,点确定或按ENTER回车键。
唤出CMD后输入下面命令后按回车键:
cd C:\Program Files\Java\jdk1.7.0\bin
输入后,按回车;
再输入下面命令后,按回车:
jarsigner-verbose -keystore abc.keystore -signedjar 123x.apk new_target.apk abc.keystore
接着,输入密码按回车。
这样,就可以生成签名的apk文件了。这里输入文件abc.apk,最终生成123x.apk,为android签名后的APK执行文件。下面提示输入的密码和keytool输入的一样就行了 。
如果是修改APK或ZIP格式刷机ROM,需要签名,推荐用auto-sign签名,简单方便:
下载 auto-sign.zip ;
运行需安装JAVA jdk;
auto-sign解压到如E盘下;
将需要签名的APK或ZIP放到 auto-sign签名工具同目录下;
运行auto-sign签名批处理工具即可自动签名。
安装APK测试
Adb install 123x.apk
安卓设备上运行重打包过的apk正常登录,提示签名错误,说明APK文件有检查apk的签名,第一步绕过重打包签名验证。
开始逆向和反编译破解加密解密的数据
抓取登录数据包:
下载数据包抓取工具charles,工具的使用请自行搜索;
通过数据包,发现登录请求的数据回答是显示签名错误。
开始对比正常的数据包—— 一个正常登录的数据包,里面的数据是被加密过的;
开始尝试解密数据包,先反编译APK。如果没被加密,反编译的方法请自行搜索;
开始寻找APK里面的登录验证解密函数。
调试和反编译APK查看加密解密函数
先上传IDAPRO的调试支持,使用SU权限运行。
adbpush android_server /data/local/tmp/
adbshell chmod 777 /data/local/tmp/android_server
su /data/local/tmp/android_server
adb forward tcp:23946 tcp:23946
运行adb logcat ActivityManager:I *:s查看Android应用包/Activity。
再运行命令,等待IDAPRO附加调试:
adb shell am start-D -n com.cyjh.gundam/.fengwo.ui.activity.WelcomeActivity
IDAPRO附加进程命令:
Debugger - > Attach -> RemoteArmLinux/Android debugger
这种方法尝试之后好像不能调试到Dalvik虚拟机。
现在开始dex文件的反编译-dex2jar和jd-gui:
d2j-dex2jar.bat classes2.dex生成classes2-dex2jar.jar
下载jd-gui打开classes2-dex2jar.jar
写个SOHOOK掉解密函数
下载
xposed(http://repo.xposed.info/module/de.robv.android.xposed.installer)
编译一个Hook插件拦截解密函数,分析整理解密函数与原始数据包并对应到URL
(范例:https://github.com/jackuhan/LoginHook)
去掉APK自校验重新打包(lib/xxx/libcjencrypt.so)
.text:F3E69478decrypt; DATA XREF: .data:F3E7D030↓o
.text:F3E69478;__unwind {
.text:F3E69478PUSH {R4-R7,LR}
.text:F3E6947AADD R7, SP, #0xC
.text:F3E6947CPUSH.W {R8,R9,R11}
.text:F3E69480MOV R9, R1
.text:F3E69482MOV R1, R3
.text:F3E69484MOV R8, R2
.text:F3E69486MOV R6, R0
.text:F3E69488BL sub_F3E694C4
.text:F3E6948CMOV R4, R0
.text:F3E6948ELDR R0, =(off_F3E7D004 - 0xF3E69494)
.text:F3E69490ADD R0, PC;off_F3E7D004
.text:F3E69492LDR R1, [R0]; "8CF8BD517174351E61BBCF776B3B83376195D65"
.text:F3E69494MOV R0, R4; s1
.text:F3E69496BLX strcmp; apk checksum
.text:F3E6949AMOV R5, R0
.text:F3E6949CMOV R0, R4; ptr
.text:F3E6949EBLX free
.text:F3E694A2CBZ R5, loc_F3E694AC
.text:F3E694A4MOVS R0, #0
.text:F3E694A6POP.W {R8,R9,R11}
.text:F3E694AAPOP {R4-R7,PC}
.text:F3E694AC;---------------------------------------------------------------------------
.text:F3E694AC
.text:F3E694ACloc_F3E694AC; CODE XREF:decrypt+2A↑j
.text:F3E694ACMOV R0, R6
.text:F3E694AEMOV R1, R9
.text:F3E694B0MOV R2, R8
.text:F3E694B2POP.W {R8,R9,R11}
.text:F3E694B6POP.W {R4-R7,LR}
.text:F3E694BAB.W sub_F3E68C88
.text:F3E694BA; Endof function decrypt
VIP权限
.methodpublic setIsVip(I)V
.locals 4
.param p1, "isVip" # I
.prologue
.line 274
iput p1, p0, Lcom/cyjh/gundam/model/UserInfo;->IsVip:I
constv0, 0x1
iputv0, p0, Lcom/cyjh/gundam/model/UserInfo;->IsVip:I
.line 275
return-void
.end method
CODE:00704F1C# Source file: UserInfo.java
CODE:00704F1Cpublic int com.cyjh.gundam.model.UserInfo.getIsVip()
CODE:00704F1Cthis =v1 # CODE XREF: VipPresenter_setUserInfo@VL+A↑p
CODE:00704F1C # LeftMenuFragment_setInfo@VL:loc_6BE372↑p ...
CODE:00704F1C .prologue_end
CODE:00704F1C .line 270
CODE:00704F1C iget v0, this, stru_B09E4
CODE:00704F20 const/4 v0, 1
CODE:00704F22
CODE:00704F22locret:
CODE:00704F22 return v0
CODE:00705046Method End
VIP过期时间
.methodpublic setVIPExpireTime(Ljava/lang/String;)V
.locals 4
.param p1, "VIPExpireTime" # Ljava/lang/String;
.prologue
.line 282
iput-object p1, p0,Lcom/cyjh/gundam/model/UserInfo;->VIPExpireTime:Ljava/lang/String;
const-string/jumbov0, "2022-12-31"
iputv0, p0, Lcom/cyjh/gundam/model/UserInfo;->VIPExpireTime:Ljava/lang/String;
.line 283
return-void
.endmethod
CODE:0070503C
CODE:0070503Cpublic java.lang.String com.cyjh.gundam.model.UserInfo.getVIPExpireTime()
CODE:0070503Cthis =v1
CODE:0070503C
CODE:0070503C .prologue_end
CODE:0070503C .line 278
CODE:0070503C iget-object v0, this, stru_B0A4C
CODE:00705040 const-string/jumbo v0, a20221231
CODE:00705046
CODE:00705046locret:
CODE:00705046 return-object v0
CODE:00705046Method End
VIP类型
.methodpublic setVIPType(I)V
.locals 4
.param p1, "VIPType" # I
.prologue
.line 110
iput p1, p0, Lcom/cyjh/gundam/model/UserInfo;->VIPType:I
constv0, 0x2
iputv0, p0, Lcom/cyjh/gundam/model/UserInfo;->VIPType:I
.line 111
return-void
.endmethod
CODE:00705058
CODE:00705058public int com.cyjh.gundam.model.UserInfo.getVIPType()
CODE:00705058this =v1
CODE:00705058
CODE:00705058 .prologue_end
CODE:00705058 .line 106
CODE:00705058 iget v0, this, stru_B0A54
CODE:0070505C const/4 v0, 2
CODE:0070505E
CODE:0070505Elocret:
CODE:0070505E return v0
CODE:0070505EMethod End
去除时间限制
com.cyjh.gundam.manager.LoginManager.java
.methodpublic getDisCountSecond()J
.locals 2
.prologue
.line 965
invoke-virtual {p0}, Lcom/cyjh/gundam/manager/LoginManager;->isLoginV70()Z
move-result v0
if-eqz v0, :cond_0
.line 966
iget-object v0, p0,Lcom/cyjh/gundam/manager/LoginManager;->mInfo:Lcom/cyjh/gundam/model/LoginResultInfo;
iget-wide v0, v0, Lcom/cyjh/gundam/model/LoginResultInfo;->DisCountSecond:J
.line 968
:goto_0
const-wide/32v0, 0x10000
return-wide v0
:cond_0
const-wide/16 v0, 0x0
const-wide/32v0, 0x10000
goto :goto_0
.endmethod
.methodpublic getFreeSecond()J
.locals 2
.prologue
.line 975
invoke-virtual {p0}, Lcom/cyjh/gundam/manager/LoginManager;->isLoginV70()Z
move-result v0
if-eqz v0, :cond_0
.line 976
iget-object v0, p0,Lcom/cyjh/gundam/manager/LoginManager;->mInfo:Lcom/cyjh/gundam/model/LoginResultInfo;
iget-wide v0, v0, Lcom/cyjh/gundam/model/LoginResultInfo;->FreeSecond:J
.line 978
:goto_0
const-wide/32v0, 0x10000
return-wide v0
:cond_0
const-wide/16 v0, 0x0
const-wide/32v0, 0x10000
goto :goto_0
.endmethod
免登录打开脚本支持的游戏
a) 源码文件夹
com.cyjh.gundam.fengwo,“com\cyjh\gundam\fengwo”
b) 搜索isLoginV70函数调用,smali里面修改返回值免登录。
"我的脚本" 免登录
a) 源码
com.cyjh.gundam.utils.IntentUtil.java
b) 定位函数toMyScriptActivity里面的isLoginV70,修改返回值
强制免费使用脚本
a) 源码文件夹
com\cyjh\gundam\fengwoscript\
b) 搜索isLogin函数调用, 修改返回值。
c) 源码文件夹
(com.cyjh.gundam.fengwoscript.model.manager.HeartAndPermManager.java)
d) 搜索函数checkRunPerm,修改里面的判断语句
viprunperminfo.KickedOut
viprunperminfo.BanRun
viprunperminfo.TryExpired
实现强制选择目标脚本,进入“本地挂机”按钮界面,按钮默认状态被禁止。
e) 源码文件夹
com.cyjh.gundam.fengwoscript.ui.help.SzScriptInfoSetHelp.java
f) 搜索函数setInfo,修改vipadresultinfo.RunPerm.Run和vipadresultinfo.RunPerm.Try实现恢复“本地挂机”按钮,但是无法弹出外挂对话框。
g) 源码文件夹
com.cyjh.gundam.fengwoscript.model.manager.HeartAndPermManager.java
h) 找到函数isRun,修改viprunperminfo.KickedOut、viprunperminfo.BanRun、viprunperminfo.TryExpired,实现弹出外挂设置对话框。
i) 源码文件夹
(com.cyjh.gundam.fengwo.pxkj.script.ui.presenter.ScriptRunPresenter.java)
j) 搜索vipadresultinfo.RunPerm.KickedOut,修改掉判断语句。
k) 源码文件夹
(com.cyjh.gundam.fengwoscript.presenter.ScriptInfoPresenter.java)
l) 找到函数startScriptOnClick,修改vipadresultinfo.RunPerm.Run和vipadresultinfo.RunPerm.Try
触发“本地挂机”按钮事件强制运行脚本,脚本运行后马上停止。
m) 源码文件夹
(com.cyjh.gundam.fengwoscript.model.manager.HeartAndPermManager.java)
n) 搜索onEventMainThread检测线程函数,修改vipscriptheartinfo.Status状态值为3,即可实现强制使用脚本.
o) 找到源码文件夹
(com.cyjh.gundam.activity.GunDamMainActivity.java)
p) 定位到函数setBottomDataByPreData,(首页、"TargetType": 6),(云手机、TargetType": 8),(我的、"TargetType":7,),(免Root脚本、"TargetType":11),(变态游戏、 "TargetType":9),分别对应到APK的底下菜单栏处理。
q) 找到源码文件夹
(com.cyjh.gundam.fengwoscript.ui.help.SzScriptInfoSetHelp.java)
r) 找到函数setInfo,修改vipadresultinfo.EachTryTime语句关闭剩余试用的提示。
s) 找到源码文件夹
(com.cyjh.gundam.fengwoscript.ui.help.ScriptTopRaqViewHelp.java)
t) 找到函数setData,改为mFaqTv.setVisibility(0)关闭脚本使用常见问题.
u) 找到源码文件夹
(com.cyjh.gundam.fengwoscript.presenter.ScriptInfoPresenter.java)
v) 找到函数isShowAd,改为返回false关闭非会员运行脚本展示广告。
心跳包线程
com.cyjh.gundam.fengwoscript.presenter.ScriptInfoPresenter.java
{
booleanflag = true;
Strings = com/cyjh/gundam/fengwoscript/presenter/ScriptInfoPresenter.getSimpleName();
StringBuilderstringbuilder = (new StringBuilder()).append("PermStatueEvent --\u5FC3\u8DF3\u662F\u5426\u8C03\u7528\uFF1A");
if(permstatueevent.resultInfo!= null)
flag= false;
CLog.i(s,stringbuilder.append(flag).toString());
try
{
SZScriptInfoszscriptinfo = permstatueevent.resultInfo.ScriptInfo;
if(szscriptinfo!= null)
{
mInfo.EncryptKey= szscriptinfo.EncryptKey;
mInfo.IsEncrypt= szscriptinfo.IsEncrypt;
mInfo.NewEncryptKey= szscriptinfo.NewEncryptKey;
mInfo.ScriptPath= szscriptinfo.ScriptPath;
loadScript(true);
}else
{
loadScript(false);
}
}
catch(Exceptionexception) { }
}
心跳包检测跳过
com.cyjh.gundam.fengwoscript.model.ScriptHeartModel.java
以下4个函数直接返回:
.methodprivate load()V
.locals 1
.prologue
.line 137
return-void
iget-object v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mListener:Lcom/kaopu/core/basecontent/http/inf/IUIDataListener;
invoke-virtual {p0, v0},Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->loadData(Lcom/kaopu/core/basecontent/http/inf/IUIDataListener;)V
.line 138
return-void
.endmethod
.methodprivate pauseHear()V
.locals 0
.prologue
.line 116
return-void
invoke-direct {p0},Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->removeHeart()V
.line 117
return-void
.endmethod
.methodprivate resumeHear()V
.locals 2
.prologue
.line 122
return-void
const/4 v0, 0x2
iput v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mStartOrStop:I
.line 123
iget-object v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mPathModel:Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartPathModel;
const/4 v1, 0x0
invoke-virtual {v0, v1},Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartPathModel;->setCount(I)V
.line 128
iget v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mHeartbeatInterval:I
if-gtz v0, :cond_0
.line 129
const/16 v0, 0x12c
iput v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mHeartbeatInterval:I
.line 131
:cond_0
iget v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mHeartbeatInterval:I
mul-int/lit16 v0, v0, 0x3e8
invoke-direct {p0, v0},Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->sendHeartHandler(I)V
.line 132
return-void
.endmethod
.methodpublic startHear(I)V
.locals 3
.param p1, "time" # I
.prologue
return-void
const/4 v2, 0x1
.line 108
iput p1, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mHeartbeatInterval:I
.line 109
iput v2, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mStartOrStop:I
.line 110
iget-object v0, p0,Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->mPathModel:Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartPathModel;
const/4 v1, 0x0
invoke-virtual {v0, v1},Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartPathModel;->setCount(I)V
.line 111
invoke-direct {p0, v2},Lcom/cyjh/gundam/fengwoscript/model/ScriptHeartModel;->sendHeartHandler(I)V
.line 112
return-void
.endmethod
免登录运行脚本分析
PXJY脚本心跳请求:
目录:
com.cyjh.gundam.fengwo.pxkj.script.ui.presenter
源码:
ScriptInfoViewPresenter.java ScriptHeartAndPermManager.java
ScriptManager.java
ScriptRunPermModel.java
ScriptInfoViewPresenter.java
加载脚本心跳请求函数:
public void load()
{
iView.showLoading();
ScriptHeartAndPermManager.getInstance().loadScriptPerm();
}
开始函数
public void start()
{
Log.i(com/cyjh/gundam/fengwo/pxkj/script/ui/presenter/ScriptInfoViewPresenter.getSimpleName(),"start()");
mInfo =CurrOpenAppManager.getInstance().getScriptInfo();
mScriptFileCompleteReceiver.registerReceiver(BaseApplication.getInstance(), newIntentFilter("pxkj_action_script_file_complete"));
IntentFilterintentfilter = new IntentFilter();
intentfilter.addAction("0x1_scriptinfo");
LocalBroadcastManager.getInstance(iView.getCurrentContext()).registerReceiver(mScriptInfoReceiver,intentfilter);
load();
}
ScriptHeartAndPermManager.java
发送GetRunPerm心跳请求
public void loadScriptPerm()
{
mRunPermModel = newScriptRunPermModel(CurrOpenAppManager.getInstance().getScriptInfo());
mRunPermModel.load();
}
收到心跳回答包,并且发送toLocalBradcastForScriptInfo通知脚本信息:
public voiduiDataSuccess(Object obj)
{
isRunPermLoading =false;
BaseResultWrapperbaseresultwrapper = (BaseResultWrapper)obj;
if(baseresultwrapper!= null && baseresultwrapper.code.intValue() == 1)
{
VipAdResultInfovipadresultinfo = (VipAdResultInfo)baseresultwrapper.data;
if(vipadresultinfo!= null && vipadresultinfo.ScriptInfo != null)
IntentUtil.toLocalBradcastForScriptInfo(1, vipadresultinfo.ScriptInfo);
else
IntentUtil.toLocalBroadcastForScriptperm(vipadresultinfo);
}
}
ScriptInfoViewPresenter.java
接受toLocalBradcastForScriptInfo通知信息,并下载脚本。
public voidonReceive(Context context, Intent intent)
{
Log.i(com/cyjh/gundam/fengwo/pxkj/script/ui/presenter/ScriptInfoViewPresenter.getSimpleName(),"onrecive:");
SZScriptInfoszscriptinfo =(SZScriptInfo)intent.getParcelableExtra("0x1_key_scriptinfo_bundle");
if(szscriptinfo !=null)
{
mInfo.EncryptKey= szscriptinfo.EncryptKey;
mInfo.EncryptKey= szscriptinfo.NewEncryptKey;
mInfo.ScriptPath= szscriptinfo.ScriptPath;
mInfo.IsEncrypt= szscriptinfo.IsEncrypt;
loadScript();
}
}
FengWoScript心跳检查:
com.cyjh.gundam.fengwoscript.presenter.ScriptInfoPresenter.java
public voidonEventMainThread(com.cyjh.gundam.fengwoscript.event.Event.PermStatueEventpermstatueevent)
{
booleanflag = true;
String s= com/cyjh/gundam/fengwoscript/presenter/ScriptInfoPresenter.getSimpleName();
StringBuilder stringbuilder = (newStringBuilder()).append("PermStatueEvent --\u5FC3\u8DF3\u662F\u5426\u8C03\u7528\uFF1A");
if(permstatueevent.resultInfo != null)
flag =false;
CLog.i(s, stringbuilder.append(flag).toString());
try
{
SZScriptInfoszscriptinfo = permstatueevent.resultInfo.ScriptInfo;
if(szscriptinfo!= null)
{
mInfo.EncryptKey = szscriptinfo.EncryptKey;
mInfo.IsEncrypt = szscriptinfo.IsEncrypt;
mInfo.NewEncryptKey = szscriptinfo.NewEncryptKey;
mInfo.ScriptPath = szscriptinfo.ScriptPath;
loadScript(true);
}else
{
loadScript(false);
}
}
catch(Exception exception) { }
}
协议回答的UUID检查绕过
源码文件夹:
com.cyjh.gundam.utils.UUIDManager.java
修改UUIDManager.getInstance().isExist的返回值为true
修改UUIDManager.getInstance().generateUUID生成一个固定UUID
“1c59f8d2-a569-4968-ba4c-89488b3f1f34”
跳过对GetRunPerm协议的处理
源码文件夹:
com/cyjh/gundam/utils/DesUtils.java
找到解密函数decode_new,修改其让其跳过对GetRunPerm协议的回答进行解密,我们的服务器返回明文字符串,让其正常解析。下面是添加后的代码:
.methodpublicdecode_new2(Ljava/lang/String;Landroid/content/Context;)Ljava/lang/String;
.locals 4
.param p1, "paramString"
.param p2, "paramContext"
.prologue
.line 41
const-string/jumbo v2, "myhook"
const-string/jumbo v3, "decode_new"
invoke-static {v2, v3},Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 42
const-string/jumbo v0, "1c59f8d2-a569-4968-ba4c-89488b3f1f34"
.line 43
.local v0, "code":Ljava/lang/String;
const/4 v2, 0x0
const/16 v3, 0x24
invoke-virtual {p1, v2, v3},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v1
.line 45
.local v1, "str2":Ljava/lang/String;
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-eqz v2, :cond_0
.line 49
.end local p1
:goto_0
return-object p1
.restart local p1
:cond_0
const-string/jumbo p1, ""
goto :goto_0
.end method
.methodpublic decode_new(Ljava/lang/String;Landroid/content/Context;)Ljava/lang/String;
.locals 4
.param p1, "data"
.param p2, "context"
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/lang/Exception;
}
.end annotation
.prologue
.line 130
invoke-static {p1},Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v2
if-eqz v2, :cond_0
.line 131
const-string/jumbo v2, ""
.line 152
:goto_0
return-object v2
:cond_0
invoke-virtual {p0, p1, p2},Lcom/mfwfz/game/utils/DesUtils;->decode_new2(Ljava/lang/String;Landroid/content/Context;)Ljava/lang/String;
move-result-object v0
.local v0, "str":Ljava/lang/String;
if-eqz v0, :cond_3
.line 58
.end local v0
return-object v0
.restart local v0
.line 134
:cond_3
if-nez p2, :cond_2
.line 135
invoke-static {},Lcom/mfwfz/game/application/BaseApplication;->getInstance()Lcom/mfwfz/game/application/BaseApplication;
move-result-object v2
if-nez v2, :cond_1
.line 136
const-string/jumbo v2, "decode"
const-string/jumbo v3, "\u62a5\u9519decode: context=null"
invoke-static {v2, v3},Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
.line 137
const-string/jumbo v2, ""
goto :goto_0
.line 139
:cond_1
invoke-static {},Lcom/mfwfz/game/application/BaseApplication;->getInstance()Lcom/mfwfz/game/application/BaseApplication;
move-result-object p2
.line 143
:cond_2
:try_start_0
new-instance v0, Lcom/cyjh/cjencrypt/CJEncrypt;
invoke-direct {v0}, Lcom/cyjh/cjencrypt/CJEncrypt;-><init>()V
.line 144
.local v0, "cjEncrypt":Lcom/cyjh/cjencrypt/CJEncrypt;
invoke-virtual {v0, p1},Lcom/cyjh/cjencrypt/CJEncrypt;->setSource(Ljava/lang/String;)V
.line 145
const/4 v2, 0x2
invoke-virtual {v0, v2}, Lcom/cyjh/cjencrypt/CJEncrypt;->setCryptType(I)V
.line 146
const/4 v2, 0x0
invoke-virtual {v0, v2}, Lcom/cyjh/cjencrypt/CJEncrypt;->setPurpose(I)V
.line 147
const/4 v2, 0x0
invoke-virtual {v0, v2}, Lcom/cyjh/cjencrypt/CJEncrypt;->setIndex(I)V
.line 148
new-instance v2, Lcom/cyjh/cjencrypt/EncryptJni;
invoke-direct {v2}, Lcom/cyjh/cjencrypt/EncryptJni;-><init>()V
invoke-virtual {v2, v0, p2},Lcom/cyjh/cjencrypt/EncryptJni;->Encrypt(Lcom/cyjh/cjencrypt/CJEncrypt;Landroid/content/Context;)Ljava/lang/String;
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
move-result-object v2
goto :goto_0
.line 149
.end local v0
:catch_0
move-exception v1
.line 150
.local v1, "e":Ljava/lang/Exception;
invoke-virtual {v1}, Ljava/lang/Exception;->printStackTrace()V
.line 152
const-string/jumbo v2, ""
goto :goto_0
.end method
反编译修改包名
利用apktool拆包
首先更改AndroidManifest.xml里面的包名
全局更改com.xxx.xxxx类似的包名
全局更改smali类型代码的包名字符串Lcom/xxx/xxxx
全局更改所有com/xxx/xxxx文件夹的名称,因为java文件里面要求包名和文件夹路径要对应
apktoolb打包apk
jarsigner 签名 ,安装apk
KILL掉统计信息
替换程序中的url
url被加密则让其url加载错误
屏蔽掉开启外挂后回到游戏蜂窝
源码文件夹:
Lcom/mfwfz/game/fengwoscript/ui/help/ScriptTopViewHelp
找到两个函数setData,找到内部调用,改为红色字体的值:
去广告的另一种方式
修改android窗口布局的xml文件,本例去掉云挂机的广告(cloud_hook_entry_view.xml)(见下面的红色字体部分):
关闭打开APP时弹出的“游戏蜂窝”加密广播
源码文件夹:
com/mfwfz/game/manager/alarmtask/AlarmTaskManager.java
找到函数showTaskNotification直接返回。
找按钮事件的另一种方式
先找到按钮所在窗口的xml布局文件(一般res目录下),然后人工分析窗口的xml布局找到按钮的ID,再通过ID找到按钮的十六进制值,本例用“楚留香”挂机示范。
如果不能直接找到“云挂机”的按钮ID值和ID名称,先找左边的“本地挂机”ID名称“go_run_script_ly”,然后res目录搜索“go_run_script_ly”就能找到“云挂机”的ID名称“go_run_ygj_btn”,再然后搜索ID值就能找到相应的按钮事件。
更改AndroidManifest.xml的版本号
先使用AXMLPrinter2.jar,还原二进制的AndroidManifest.xml,到字符串的AndroidManifest.xml.java -jar AXMLPrinter2.jar AndroidManifest.xml >newxml.xml
然后打开WinHex搜索版本字符串,本例修改了两处“3.1.9升级为3.2.0”,如下图:
第一处:
第二处:
云手机试用时间限制
com\cyjh\gundam\fengwo\presenter\cloud\CloudHookHomePagePresenter.javaorderInfo.TryMinute
游戏蜂窝的技术优势
所有信息均从web服务器取到本地,也就是Google和Apple推荐的这种信息安全存取方式。
一个帐号登录之后没有退出按钮,从根本上杜绝了垃圾帐号或者一台设备登录多个帐号的可能性;设备每次登录服务端都会判断设备是否在线,然后踢下在线的设备,保持一个帐号只能同时登录一个设备。
每条发送到服务端的协议均有签名,签名不对的时候服务器拒绝回答。这里有个BUG,它是判断APK的自签名是不是与特定值有效,无效就拒绝计算协议的签名,其实应该把计算出来APK包的签名值也带入协议中,放在服务器做判断APK包是否被修改过。
判断自校验的代码没有做自校验,导致可以被随便修改。
协议防重放攻击。
游戏蜂窝的技术劣势
不会善用APK加固程序,就算免费的也能做到很好的对抗APK包修改者,可能兼容性有一定的下降。
看雪ID:猪会被杀掉
https://bbs.pediy.com/user-687175.htm
本文由看雪论坛 猪会被杀掉 原创
转载请注明来自看雪社区
热门技术文章推荐: