: :其他软件 2019-08-30 12:34:14
1.静态分析:
分别用AK,JADX,JEB加载文件看看
(1)JADX
(2)AK
(3)JEB
jadx和AK明显分析难度很高,果断放弃,选用JEB查看
2.分析oncreat函数
好的,我们发现了几个比较可疑的函数,PatchProxy,changeQuickRedirect,[size=13.475px]runrobust;其中[size=13.475px]runrobust有lmp标识,这个是动态加载的特征
public
void
onCreate(Bundle arg13) {
int
v4 =
3
;
Object[] v0 =
new
Object[
1
];
v0[
0
] = arg13;
ChangeQuickRedirect v2 = MainActivity.changeQuickRedirect;
Class[] v5 =
new
Class[
1
];
Class v1 = Bundle.
class
;
v5[
0
] = v1;
Class v6 = Void.TYPE;
MainActivity v1_1 =
this
;
boolean
v0_1 = PatchProxy.isSupport(v0, v1_1, v2,
false
, v4, v5, v6);
if
(v0_1) {
v0 =
new
Object[
1
];
v0[
0
] = arg13;
v2 = MainActivity.changeQuickRedirect;
v5 =
new
Class[
1
];
v1 = Bundle.
class
;
v5[
0
] = v1;
v6 = Void.TYPE;
v1_1 =
this
;
PatchProxy.accessDispatch(v0, v1_1, v2,
false
, v4, v5, v6);
}
else
{
int
v0_2 =
2
;
String v9 =
this
.Joseph(
1
, v0_2);
super
.onCreate(arg13);
v0_2 =
0x7F09001B
;
this
.setContentView(v0_2);
this
.runRobust();
String v0_3 =
"1B:D0:4A:9D:B5:A9:84:93:7E:79:27:9C:6C:C4:14:AB:DD:B0:75:7F"
;
SignCheck v10 =
new
SignCheck(
this
, ((Context)
this
), v0_3);
v10.check();
Debug.isDebuggerConnected();
v0_2 =
0x7F07003D
;
View v8 =
this
.findViewById(v0_2);
v0_2 =
0x7F070026
;
View v7 =
this
.findViewById(v0_2);
cn.chaitin.geektan.crackme.MainActivity$
1
v0_4 =
new
View$OnClickListener(((EditText)v8), v9) {
public
static
ChangeQuickRedirect changeQuickRedirect;
public
void
onClick(View arg9) {
Toast v0_6;
MainActivity v0_5;
String v1_3;
int
v4 =
18
;
Object[] v0 =
new
Object[
1
];
v0[
0
] = arg9;
ChangeQuickRedirect v2 = cn.chaitin.geektan.crackme.MainActivity$
1
.changeQuickRedirect;
Class[] v5 =
new
Class[
1
];
Class v1 = View.
class
;
v5[
0
] = v1;
Class v6 = Void.TYPE;
cn.chaitin.geektan.crackme.MainActivity$
1
v1_1 =
this
;
boolean
v0_1 = PatchProxy.isSupport(v0, v1_1, v2,
false
, v4, v5, v6);
if
(v0_1) {
v0 =
new
Object[
1
];
v0[
0
] = arg9;
v2 = cn.chaitin.geektan.crackme.MainActivity$
1
.changeQuickRedirect;
v5 =
new
Class[
1
];
v1 = View.
class
;
v5[
0
] = v1;
v6 = Void.TYPE;
v1_1 =
this
;
PatchProxy.accessDispatch(v0, v1_1, v2,
false
, v4, v5, v6);
}
else
{
EditText v0_2 =
this
.val$input_text;
Editable v0_3 = v0_2.getText();
v0_1 = TextUtils.isEmpty(((CharSequence)v0_3));
if
(!v0_1) {
v0_2 =
this
.val$input_text;
v0_3 = v0_2.getText();
String v0_4 = v0_3.toString();
StringBuilder v1_2 =
new
StringBuilder();
String v2_1 =
"DDCTF{"
;
v1_2 = v1_2.append(v2_1);
v2_1 =
this
.val$result;
v1_2 = v1_2.append(v2_1);
v2_1 =
"}"
;
v1_2 = v1_2.append(v2_1);
v1_3 = v1_2.toString();
v0_1 = v0_4.equals(v1_3);
if
(v0_1) {
v0_5 = MainActivity.
this
;
v1_3 =
"恭喜大佬!密码正确!"
;
v0_6 = Toast.makeText(((Context)v0_5), ((CharSequence)v1_3),
0
);
v0_6.show();
return
;
}
}
v0_5 = MainActivity.
this
;
v1_3 =
"大佬莫急!再试试!"
;
v0_6 = Toast.makeText(((Context)v0_5), ((CharSequence)v1_3),
0
);
v0_6.show();
}
}
};
((Button)v7).setOnClickListener(((View$OnClickListener)v0_4));
}
}
可以看到此函数实例化了PatchManipulateImp(),我们跟进去看看;
private
void
runRobust() {
int
v4 =
4
;
Object[] v0 =
new
Object[
0
];
ChangeQuickRedirect v2 = MainActivity.changeQuickRedirect;
Class[] v5 =
new
Class[
0
];
Class v6 = Void.TYPE;
MainActivity v1 =
this
;
boolean
v0_1 = PatchProxy.isSupport(v0, v1, v2,
false
, v4, v5, v6);
if
(v0_1) {
v0 =
new
Object[
0
];
v2 = MainActivity.changeQuickRedirect;
v5 =
new
Class[
0
];
v6 = Void.TYPE;
v1 =
this
;
PatchProxy.accessDispatch(v0, v1, v2,
false
, v4, v5, v6);
}
else
{
Context v1_1 =
this
.getApplicationContext();
PatchManipulateImp v2_1 =
new
PatchManipulateImp();
PatchExecutor v0_2 =
new
PatchExecutor(v1_1, ((PatchManipulate)v2_1),
new
GeekTanCallBack());
v0_2.start();
}
}
}
this.applyPatchList(this.fetchPatchList());就是打补丁的操作,跟进去看看
public
void
run() {
try
{
this
.applyPatchList(
this
.fetchPatchList());
}
catch
(Throwable v1) {
String v2 =
"robust"
;
String v3 =
"PatchExecutor run"
;
Log.e(v2, v3, v1);
RobustCallBack v2_1 =
this
.robustCallBack;
v3 =
"class:PatchExecutor,method:run,line:36"
;
v2_1.exceptionNotify(v1, v3);
}
}
再定位到载入的位置
protected
void
applyPatchList(List arg9) {
RobustCallBack v4_4;
boolean
v0;
String v6;
StringBuilder v5_2;
if
(arg9 !=
null
) {
boolean
v3 = arg9.isEmpty();
if
(v3) {
return
;
}
String v3_1 =
"robust"
;
StringBuilder v4 =
new
StringBuilder();
String v5 =
" patchManipulate list size is "
;
v4 = v4.append(v5);
int
v5_1 = arg9.size();
v4 = v4.append(v5_1);
String v4_1 = v4.toString();
Log.d(v3_1, v4_1);
Iterator v3_2 = arg9.iterator();
label_98:
boolean
v4_2 = v3_2.hasNext();
if
(!v4_2) {
return
;
}
Object v1 = v3_2.next();
v4_2 = ((Patch)v1).isAppliedSuccess();
if
(v4_2) {
v4_1 =
"robust"
;
v5_2 =
new
StringBuilder();
v6 =
"p.isAppliedSuccess() skip "
;
v5_2 = v5_2.append(v6);
v6 = ((Patch)v1).getLocalPath();
v5_2 = v5_2.append(v6);
v5 = v5_2.toString();
Log.d(v4_1, v5);
goto
label_98;
}
PatchManipulate v4_3 =
this
.patchManipulate;
v4_2 = v4_3.ensurePatchExist(((Patch)v1));
if
(!v4_2) {
goto
label_98;
}
try
{
v0 =
this
.patch(
this
.context, ((Patch)v1));
}
catch
(Throwable v2) {
v4_4 =
this
.robustCallBack;
v5 =
"class:PatchExecutor method:applyPatchList line:69"
;
v4_4.exceptionNotify(v2, v5);
}
if
(v0) {
((Patch)v1).setAppliedSuccess(
true
);
v4_4 =
this
.robustCallBack;
v4_4.onPatchApplied(
true
, ((Patch)v1));
}
else
{
v4_4 =
this
.robustCallBack;
v4_4.onPatchApplied(
false
, ((Patch)v1));
}
v4_1 =
"robust"
;
v5_2 =
new
StringBuilder();
v6 =
"patch LocalPath:"
;
v5_2 = v5_2.append(v6);
v6 = ((Patch)v1).getLocalPath();
v5_2 = v5_2.append(v6);
v6 =
",apply result "
;
v5_2 = v5_2.append(v6);
v5_2 = v5_2.append(v0);
v5 = v5_2.toString();
Log.d(v4_1, v5);
goto
label_98;
}
}
有个path函数,点进去看看
try
{
v0 =
this
.patch(
this
.context, ((Patch)v1));
}
catch
(Throwable v2) {
v4_4 =
this
.robustCallBack;
v5 =
"class:PatchExecutor method:applyPatchList line:69"
;
v4_4.exceptionNotify(v2, v5);
}
然后可以看到DexClassLoader,这就是动态加载类了
String v18_3 = arg25.getTempPath();
File v19_2 = arg24.getCacheDir();
v19_1 = v19_2.getAbsolutePath();
v20 =
null
;
Class v21 = PatchExecutor.
class
;
ClassLoader v21_1 = v21.getClassLoader();
String v0_3 = v18_3;
String v1_1 = v19_1;
String v2_1 = v20;
ClassLoader v3 = v21_1;
DexClassLoader v5 =
new
DexClassLoader(v0_3, v1_1, v2_1, v3);
v18_3 = arg25.getTempPath();
Patch v0_4 = arg25;
v1_1 = v18_3;
v0_4.delete(v1_1);
try
{
Log.d(
"robust"
,
"PatchsInfoImpl name:"
+ arg25.getPatchesInfoImplClassFullName());
v15 = v5.loadClass(arg25.getPatchesInfoImplClassFullName()).newInstance();
Log.d(
"robust"
,
"PatchsInfoImpl ok"
);
}
catch
(Throwable v17) {
v0 =
this
;
v0_2 = v0.robustCallBack;
v18_2 = v0_2;
v19_1 =
"class:PatchExecutor method:patch line:108"
;
v0_2 = v18_2;
v1_2 = v17;
v2_1 = v19_1;
v0_2.exceptionNotify(v1_2, v2_1);
v18_3 =
"robust"
;
v19 =
new
StringBuilder();
v20 =
"PatchsInfoImpl failed,cause of"
;
v19 = v19.append(v20);
v20 = v17.toString();
v19 = v19.append(v20);
v19_1 = v19.toString();
Log.e(v18_3, v19_1);
v17.printStackTrace();
}
结果就是Joseph(int,int)
String
str
=
"DDCTF{"
;
str
= (String) EnhancedRobustUtils.invokeReflectMethod(
"Joseph"
, obj32, getRealParameter(new Object[]{new Integer(7), new Integer(8)}), new Class[]{Integer
.TYPE
, Integer
.TYPE
}, MainActivity.class);
if
(obj4 ==
this
) {
obj4 = ((MainActivity
$
1Patch) obj4).originClass;
}
if
(((Boolean) EnhancedRobustUtils.invokeReflectMethod(
"equals"
, obj2, getRealParameter(new Object[]{str2}), new Class[]{Object.class}, String.class)).booleanValue()) {
if
(
this
instanceof MainActivity
$
1Patch) {
obj2 =
this
.originClass;
}
else
{
obj2 =
this
;
}
obj2 = (Toast) EnhancedRobustUtils.invokeReflectStaticMethod(
"makeText"
, Toast.class, getRealParameter(new Object[]{(MainActivity) EnhancedRobustUtils.getFieldValue(
"this$0"
, obj2, 1.class),
"恭喜大佬!密码正确!"
, new Integer(0)}), new Class[]{Context.class, CharSequence.class, Integer
.TYPE
});
if
(obj2 ==
this
) {
obj2 = ((MainActivity
$
1Patch) obj2).originClass;
}
EnhancedRobustUtils.invokeReflectMethod(
"show"
, obj2, new Object[0], null, Toast.class);
return;
}
最后一步,HOOK
public
static Object invokeReflectMethod(String arg5, Object arg6, Object[] arg7, Class[] arg8, Class arg9) {
Object v2;
try {
v2 = EnhancedRobustUtils.getDeclaredMethod(arg6, arg5, arg8, arg9).
invoke
(arg6, arg7);
}
catch(Exception v0) {
v0.printStackTrace();
boolean v2_1 = EnhancedRobustUtils.isThrowable;
if
(v2_1) {
StringBuilder v3 = new StringBuilder();
String v4 =
"invokeReflectMethod error "
;
v3 = v3.append(v4);
v3 = v3.append(arg5);
v4 =
" parameter "
;
v3 = v3.append(v4);
v3 = v3.append(arg7);
v4 =
" targetObject "
;
v3 = v3.append(v4);
v4 = arg6.toString();
v3 = v3.append(v4);
v4 =
" args "
;
v3 = v3.append(v4);
v3 = v3.append(arg8);
String v3_1 = v3.toString();
RuntimeException v2_2 = new RuntimeException(v3_1);
throw v2_2;
}
v2 = null;
}
return v2;
}
import
frida, sys
def
on_message(message, data):
if
message[
'type'
]
=
=
'send'
:
(
"[/i][i] {0}"
.
format
(message[
'payload'
]))
else
:
(message)
js_code
=
'''
Java.perform(function(){
var robust = Java.use("com.meituan.robust.utils.EnhancedRobustUtils");
robust.invokeReflectMethod.implementation = function(v1,v2,v3,v4,v5){
var result = this.invokeReflectMethod(v1,v2,v3,v4,v5);
if(v1=="Joseph"){
console.log("functionName:"+v1);
console.log("functionArg3:"+v3);
console.log("functionArg4:"+v4);
send(v4);
console.log("return:"+result);
console.log("-----------------------------------------------------")
}
else if(v1=="equals"){
console.log("functionName:"+v1);
console.log("functionArg3:"+v3);
console.log("functionArg4:"+v4);
send(v4);
console.log("return:"+result);
}
return result;
}
});
'''
process
=
frida.get_usb_device().attach(
"cn.chaitin.geektan.crackme"
)
(
"找到目标包"
)
script
=
process.create_script(js_code)
script.on(
'message'
, on_message)
script.load()
sys.stdin.read()
10-12vt分析pg代码
10-12clayui展示界面动态效果
10-12编译原理 词法分析
10-12编译原理 词法分析器构造
10-11动态磁场校准的九轴惯性融合
10-11算法设计与分析(第2版)在线编程题答案
10-11词法语法分析器
10-11算法设计与分析(第2版)练习题答案
10-11数据结构与算法分析C++描述
10-11简单词法分析器
10-06excel对数据进行分类汇总分析
10-04Excel动态图表添加复选框控件
10-03Excel如何制作动态图表的方法
10-03Excel中加载数据分析模块
08-30excel数据有效性常用功能详细分析
08-28ppt动态图添加方法讲解
11-28Excel给动态图表添加滚动条
11-26PPT动态按钮和超链接有什么区别