反編譯之JD-GUI程式碼邏輯分析
反編譯後程式碼:
public static void notify(Context context, String type, final String no, String money, String mark, String time) {
if ((TextUtils.isEmpty(str2)) || (TextUtils.isEmpty(str4))) {
sendmsg(context, "異常");
return;
}
String str1 = "";
String str3 = AbSharedUtil.getString(context, type + "balance");
if (type.equals("ccc")) {
str1 = AbSharedUtil.getString(context, "ccc");
}
for (; ; ) {
HttpUtils httpUtils = new HttpUtils(15000);
str4 = MD5.md5(time + mark + money + no + type + str4);
RequestParams requestParams = new RequestParams();
requestParams.addBodyParameter("balance", str3);
if (!TextUtils.isEmpty(str1)) {
requestParams.addBodyParameter("account", str1);
}
requestParams.addBodyParameter("sign", str4);
httpUtils.send(HttpRequest.HttpMethod.POST, str2, requestParams, new RequestCallBack() {
public void onFailure(HttpException paramAnonymousHttpException, String paramAnonymousString) {
update(no, paramAnonymousString);
}
public void onSuccess(ResponseInfo<String> responseInfo) {
responseInfo = (String) responseInfo.result;
for (; ; ) {
update(no, responseInfo);
return;
}
}
});
return;
if (type.equals("aaa")) {
str1 = AbSharedUtil.getString(context, "aaa");
} else if (type.equals("bbb")) {
str1 = AbSharedUtil.getString(context, "bbb");
}
}
}
原始碼:
public static void notify(final Context context, String type, final String no, String money, String mark, String time) {
if (!TextUtils.isEmpty(notifyurl) && !TextUtils.isEmpty(signkey)) {
String account = "";
String balance = AbSharedUtil.getString(context, type + "balance");
if (type.equals("ccc")) {
account = AbSharedUtil.getString(context, "ccc");
} else if (type.equals("aaa")) {
account = AbSharedUtil.getString(context, "aaa");
} else if (type.equals("bbb")) {
account = AbSharedUtil.getString(context, "bbb");
}
HttpUtils httpUtils = new HttpUtils(15000);
signkey = MD5.md5(time + mark + money + no + type + signkey);
RequestParams params = new RequestParams();
params.addBodyParameter("balance", balance);
if (!TextUtils.isEmpty(account)) {
params.addBodyParameter("account", account);
}
params.addBodyParameter("sign", signkey);
httpUtils.send(HttpMethod.POST, notifyurl, params, new RequestCallBack<String>() {
public void onFailure(HttpException e, String msg) {
update(no, msg);
}
public void onSuccess(ResponseInfo<String> resp) {
String result = (String)resp.result;
update(no, result);
}
});
} else {
sendmsg(context, "異常");
}
}
for迴圈前後對比:
public static boolean isServiceRunning(Context context, String serviceName) {
if (("".equals(serviceName)) || (serviceName == null)) {
return false;
}
context = (ArrayList) ((ActivityManager) context.getSystemService("activity")).getRunningServices(30);
int i = 0;
for (; ; ) {
if (i >= context.size()) {
return false;
}
if ((context.get(i)).service.getClassName().toString().equals(serviceName)) {
return true;
}
i += 1;
}
}
public static boolean isServiceRunning(Context context, String serviceName) {
if (!"".equals(serviceName) && serviceName != null) {
ArrayList list = (ArrayList)((ActivityManager)context.getSystemService("activity")).getRunningServices(30);
for(int i = 0; i < list.size(); ++i) {
if (list.get(i).service.getClassName().toString().equals(serviceName)) {
return true;
}
}
return false;
} else {
return false;
}
}
while迴圈前後對比:
public static int isActivityTop(Context context) {
try {
Iterator iterator = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(100).iterator();
ActivityManager.RunningTaskInfo taskInfo;
do {
if (!iterator.hasNext()) {
return 0;
}
taskInfo = (ActivityManager.RunningTaskInfo) iterator.next();
}
while (!taskInfo.topActivity.getClassName().equals("xxxyActivity"));
int i = taskInfo.numActivities;
return i;
} catch (SecurityException e) {
sendmsg(context, e.getMessage());
}
return 0;
}
public static int isActivityTop(Context context) {
try {
Iterator iterator = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(100).iterator();
while(iterator.hasNext()) {
RunningTaskInfo taskInfo = (RunningTaskInfo)iterator.next();
if (taskInfo.topActivity.getClassName().equals("xxxyActivity"));
int num = taskInfo.numActivities;
return num;
}
}
return 0;
} catch (SecurityException e) {
sendmsg(context, e.getMessage());
return 0;
}
}
用混淆器打亂的程式碼,反編譯後,要想看懂也不是一件容易的事。因為大部人都會用免費的混淆器來混淆原始碼,大部份反編譯過來的程式碼就有一定的規則可尋:
反編譯後的程式碼一般會產生以下結構的程式碼,(程式碼結構是個人總結的,如有雷同,純屬巧合)比較難看懂,本文章根據實現情況對這幾種結構做個簡單說明。
1,反編譯後的程式碼:if while結構
if (BTActivity.access$2300(this.this$0))
{
int i = BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
BTActivity.access$2500(this.this$0).notifyDataSetChanged();
}
while (true)
{
return;
Bluetooth localBt = BTActivity.access$700(this.this$0);
int k = BTActivity.access$600(this.this$0);
int l = localBt.sendCommand(1026, paramInt, k);
}
(1)只分析邏輯
這裡應該有一個if else的邏輯。從上面的程式碼分析,return下的程式碼應該是永遠不會被執行,但這是不可能的。所以上面的程式碼邏輯(我們先不看語句)應該是這樣的, 去掉while和return,加上else,修改後如下:
if (BTActivity.access$2300(this.this$0))
{
int i = BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
BTActivity.access$2500(this.this$0).notifyDataSetChanged();
}
else
{
Bluetooth localBt = BTActivity.access$700(this.this$0);
int k = BTActivity.access$600(this.this$0);
int l = localBt.sendCommand(1026, paramInt, k);
}
(2)邏輯分析完了,繼續分析語句.
A)像:int i = BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
這個是引用外部的一個類中的一個方法。然後返回整型,但這個返回值用不到,所以去掉int i
還原應該這樣:
BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
B)access$700是什麼意思呢?這是BTActivity類中的一個物件,物件有sendCommand方法。這樣就可以查BTActivity類定義的哪個物件有這樣一個方法了,這好理解。不好理解的是:int k = BTActivity.access$600(this.this$0); 中的access$600,它對應的是BTActivity中的哪個方法呢?這很難確定,所以只能猜:
1,看這個類中有多少個方法,如果只有一個,那指定就是它了。
2,如果有多個,那就要看引數。如果只有一個方法的引數與之相對應,那一定是它。
3,如果引數一樣的也有多個。那看邏輯。如果看不出來,只有猜或新增自己的邏輯。
(3)為什麼會有access$700這樣的方法/屬性名稱?原因是,呼叫者和被調者不在同一個類中。如果兩者在同一個類(包括內部類),反編譯後方法/屬性名稱不會有數字。
(4) 再舉一個更簡單的if else例
if (paramBoolean)
paramTextView.setTextColor(-16727809);
while (true)
{
return;
paramTextView.setTextColor(-1315861);
}
還原成真正的原始程式碼:
if (paramBoolean)
{
paramTextView.setTextColor(-16727809);
}
else
{
paramTextView.setTextColor(-1315861);
}
2, 反編譯後的程式碼:switch case while結構
switch (this.mBand)
{
default:
case 0:
case 1:
case 2:
}
while (true)
{
return;
this.mBand.setText("FM1");
continue;
this.mBand.setText("FM2");
continue;
this.mBand.setText("AM");
}
(1)分析邏輯:根據mBand的不同值,設定文字的顯示內容。還原成原始程式碼:
switch (mBand)
{
case 0:
mBand.setText("FM1");
break;
case 1:
mBand.setText("FM2");
break;
case 2:
mBand.setText("AM");
break;
default:
}
(2)關鍵:一個continue對你應著一個case的結束;。
3,反編譯後程式碼如下:if for while結構
int i15 = this.freq;
int i16 = this.rmin;
if (i15 < i16)
i17 = this.min;
int i29;
for (this.freq = i17; ; this.freq = i29)
{
int i27;
int i28;
do
{
this.x = getWidth();
this.y = -1;
break label32:
i27 = this.freq;
i28 = this.max;
}
while (i27 <= i28);
i29 = this.max;
}
this.y = 0;
invalidate();
(1)程式碼邏輯分析:保證freq的值在min和max之間。分析後得到的原始原始碼:
if (freq < min)
{
freq = min;
}
if (freq <= max)
{
x = getWidth();
y = -1;
}
else
{
freq = max;
y = 0;
invalidate();
}
4, 解析switch for while結構程式碼
PowerManager localPowerManager = (PowerManager)getSystemService("power");
switch (paramInt)
{
default:
case 0:
case 1:
}
for (String str = "on"; ; str = "other")
while (true)
{
PowerManager.WakeLock localWakeLock = localPowerManager.newWakeLock(6, str);
localWakeLock.acquire();
localWakeLock.release();
return;
str = "off";
}
還原原始碼:
PowerManager localPowerManager = (PowerManager)getSystemService("power");
String str = null;
switch (paramInt)
{
case 0:
str = "on";
break;
case 1:
str = "off";
break;
default:
str = "other";
break;
}
PowerManager.WakeLock localWakeLock = localPowerManager.newWakeLock(6, str);
localWakeLock.acquire();
localWakeLock.release();
5, 分析返編譯後的程式碼(if while結構)
例1:
if (paramInt1 == 0)
this.mMessage.setText("");
while (true)
{
this.mAdditionalMessage.setVisibility(8);
int i = this.mLevel.getMax();
if (paramInt2 != i)
this.mLevel.setMax(paramInt2);
Toast localToast = this.mToast;
......
return;
TextView localTextView = this.mMessage;
String str = "" + paramInt1;
localTextView.setText(str);
}
分析:1,先去掉“this"
2,看返編譯後的按順序邏輯走一遍。可以看出while到return這段程式碼,不管怎麼樣都會執行的。所以原始程式碼應該是這樣的:
setSmallIcon(paramInt1);
paramInt1 &= 2147483647;
if (paramInt1 == 0)
{
mMessage.setText("");
}
else
{
String str = "" + paramInt1;
mMessage.setText(str);
}
mAdditionalMessage.setVisibility(8);
if (paramInt2 != mLevel.getMax())
{
mLevel.setMax(paramInt2);
}
mToast.setView(mView);
......
6,一個continue對應一個back原則(switch while結構)
在這種形式中,一個contiune一定是對應一個back,但一個case不一定只對應一個contiune,也有一個case對應兩個或多個contiune(即back).
如以下反編譯後的程式碼:
分析程式碼:
1),上遍已對這種形式有講過,一個continue對應一個case,但是你數一數會發現,對不上號,明顯case多於contiune,原因是什麼呢?其實switch裡的default對應的是while中的return,在switch中default以上的case是用不著,是沒有用的。
2),如果default上面的case沒有用,聰明的你可以可能會問兩個問題?
A,default上面的case沒有用,為什麼還會有呢?原因很簡單,因為反編譯器也不是全智慧的總會有不對的(但是執行邏輯是不會有錯),呵呵真正的原因當然不會是這樣,你可以自己去分析一下,從整個程式分析就可以得出結論來。
B,那按一個continue對應一個back的原則不是有錯嗎? 當然沒有。一個continue還是對應一個back, 聰明的你一定看懂了,每兩個continue中間還有一個if語句,對,沒錯,你理解是對的,就是在這中間滿足條件時就會back,所以就會有一個continue與之相對應。
所這裡每個if + continue + continue的形式對應一個case。
二 錯誤程式碼還原規則
反編譯程式碼
if (paramBoolean)
paramTextView.setTextColor(-16727809);
while (true)
{
return;
paramTextView.setTextColor(-1315861);
} 還原後if (paramBoolean)
{
paramTextView.setTextColor(-16727809);
}
else
{
paramTextView.setTextColor(-1315861);
}
例子2:
if (responseInfo.contains("success")) {
sendmsg(this, "傳送成功" + responseInfo);
}
for (; ; ) {
update(no, responseInfo);
return;
sendmsg(this, "傳送失敗" + responseInfo); // 紅色部分對應下方else分支
}
還原後變成
if (result.contains("success")) {
sendmsg(context, "傳送成功" + result);
} else {
sendmsg(context, "傳送失敗" + result);
}
update(no, result);
if ..esle 反編譯成 if …while(true)結構.
反編譯程式碼
if (paramInt1 != 1)
break label185;
if (this.countChild_1 == null) {
this.countChild_1 = new PokerCountChild(this.mContext);
this.countChild_1.setCount(paramInt2);
addOneChild(this.countChild_1);
if (paramInt2 == 0)
this.countChild_1.setAlpha(0);
}
this.countChild_1.setCount(paramInt2);
}
label185:
do
return;
while (paramInt1 != 2);
if (this.countChild_2 == null) {
this.countChild_2 = new PokerCountChild(this.mContext);
this.countChild_2.setCount(paramInt2);
addOneChild(this.countChild_2);
if (paramInt2 == 0)
this.countChild_2.setAlpha(0);
}
this.countChild_2.setCount(paramInt2);
還原
if(i == 1) {
if(countChild_1 == null) {
countChild_1 = new PokerCountChild(mContext);
countChild_1.setCount(j);
addOneChild(countChild_1);
if(j == 0)
countChild_1.setAlpha(0);
}
countChild_1.setCount(j);
} else if(i == 2) {
if(countChild_2 == null) {
countChild_2 = new PokerCountChild(mContext);
countChild_2.setCount(j);
addOneChild(countChild_2);
if(j == 0)
countChild_2.setAlpha(0);
}
countChild_2.setCount(j);
return;
}
會將語句倒序,出現break label結構
label1:{
label2: {
if () {
break label2; //是要跳出label2,也就是label2 end的下一句
}
}//label2 end
}
另外,jd-gui有時會將while語句翻譯成if,要將if改成while
反編譯程式碼
switch (this.mBand)
{
default:
case 0:
case 1:
case 2:
}
while (true)
{
return;
this.mBand.setText("FM1");
continue;
this.mBand.setText("FM2");
continue;
this.mBand.setText("AM");
}
還原
switch (mBand)
{
case 0:
mBand.setText("FM1");
break;
case 1:
mBand.setText("FM2");
break;
case 2:
mBand.setText("AM");
break;
default:
}
switch規則就是一個continue對應一個case.要注意是是要外層的continue才算數,在if裡的continue不算
相關文章
- python反編譯之位元組碼Python編譯
- 程式碼線上編譯器(上)- 編輯及編譯編譯
- Java程式碼的編譯與反編譯那些事兒Java編譯
- Cython加密python程式碼防止反編譯加密Python編譯
- 軟體推薦-Java反編譯軟體-jd-gui(附下載地址)Java編譯GUI
- Linux程式排程邏輯與原始碼分析Linux原始碼
- 程式碼混淆防止APP被反編譯指南APP編譯
- 反編譯Android APK詳細操作指南[ApkTool,dex2jar,JD-GUI](Mac)編譯AndroidAPKJARGUIMac
- c#程式反編譯C#編譯
- 小程式反編譯教程編譯
- 簡單分析AutoIt指令碼的反編譯和程式碼格式化問題指令碼編譯
- vscode原始碼分析【二】程式的啟動邏輯VSCode原始碼
- 反編譯之安裝Apktool編譯APK
- 編碼規範:不要用引數控制程式碼邏輯
- 使用Reflector和Filedisassembler逆向編譯反編譯.cs.dll檔案程式碼編譯
- 程式碼審計之邏輯上傳漏洞挖掘
- 培養程式碼邏輯
- JS 預編譯程式碼例項分析JS編譯
- 反編譯獲取任何微信小程式原始碼編譯微信小程式原始碼
- 邏輯漏洞之密碼重置密碼
- [BUG反饋]模型編輯模板存在條件邏輯判斷錯誤模型
- Vue3 模板編譯原理 (Vue 的編譯模組整體邏輯)Vue編譯原理
- Java編譯與反編譯Java編譯
- android 反編譯APK取原始碼。Android編譯APK原始碼
- 如何反編譯微信小程式?編譯微信小程式
- Unity單例模式,但是是取自Ultrakill反編譯程式碼Unity單例模式編譯
- 安卓逆向之Luac解密反編譯安卓解密編譯
- android 反編譯Android編譯
- 錯誤程式碼的個人見解以及邏輯分析題
- 變數C++邏輯程式碼變數C++
- 微信小程式反編譯~2020年微信小程式編譯
- Android Apk反編譯系列教程(一)如何反編譯APKAndroidAPK編譯
- 微信小程式“反編譯”實戰(二):原始碼還原微信小程式編譯原始碼
- USB 邏輯分析儀分析丟包怎麼分析(lecroy USB 邏輯分析儀)
- Java 反彙編、反編譯、volitale解讀Java編譯
- Springboot中mybatis執行邏輯原始碼分析Spring BootMyBatis原始碼
- 這誰頂得住?java反編譯的彙編程式碼private volatile static Singleton instanceJava編譯
- 業務分析:HR端職位編輯薪資計算邏輯和錯誤分析