最近在分析一个加密应用的算法时,发现反编译出来的Java代码,有太多不完美的地方了,for循环尤其刺眼!我想要把相应的算法改成可编译的版本,这就需要对smali语法理解的比较透彻了。
由于手边有Android系统源码和编译好的各种模块,我可以比较容易的对照smali语句学习java代码,也可以很方便的看到对照java源码学习smali语法。
这次分析Android源码中/packages/apps/Snap/src/com/android/camera/PanoUtil.java
的一个比较简单的函数decodeYUV420SPQuarterRes
,分析几行Java代码对应的smali代码,这样有利于我们在没有源码的情况下更好的理解smali代码:
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.camera;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PanoUtil {
public static String createName(String format, long dateTaken) {
Date date = new Date(dateTaken);
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
return dateFormat.format(date);
}
// TODO: Add comments about the range of these two arguments.
public static double calculateDifferenceBetweenAngles(double firstAngle,
double secondAngle) {
double difference1 = (secondAngle - firstAngle) % 360;
if (difference1 < 0) {
difference1 += 360;
}
double difference2 = (firstAngle - secondAngle) % 360;
if (difference2 < 0) {
difference2 += 360;
}
return Math.min(difference1, difference2);
}
public static void decodeYUV420SPQuarterRes(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, ypd = 0; j < height; j += 4) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i += 4, ypd++) {
int y = (0xff & (yuv420sp[j * width + i])) - 16;
if (y < 0) {
y = 0;
}
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
uvp += 2; // Skip the UV values for the 4 pixels skipped in between
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) {
r = 0;
} else if (r > 262143) {
r = 262143;
}
if (g < 0) {
g = 0;
} else if (g > 262143) {
g = 262143;
}
if (b < 0) {
b = 0;
} else if (b > 262143) {
b = 262143;
}
rgb[ypd] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) |
((b >> 10) & 0xff);
}
}
}
}
第45行这个函数有四个参数,没有返回值:
public static void decodeYUV420SPQuarterRes(int[] rgb, byte[] yuv420sp, int width, int height){
......
}
在对应的smali代码中,四个参数分别用p0,p1,p2,p3表示:
.method public static decodeYUV420SPQuarterRes([I[BII)V
.locals 17
.param p0, "rgb" # [I
.param p1, "yuv420sp" # [B
.param p2, "width" # I
.param p3, "height" # I
......
.end method
第46行代码,两个参数相乘,赋值给另一个变量:
final int frameSize = width * height;
这个.line 46
表示下面的代码对应的Java代码在第46行,v2
代表变量frameSize
:
.prologue
.line 46
mul-int v2, p2, p3
48行,java中的一个for循环:
for (int j = 0, ypd = 0; j < height; j += 4) {
......
}
if-ge v5, v0, :cond_8
相当于java代码中的j < height
,意思是如果v5
(j
)大于等于v0
(height
)则跳转到cond_8
跳出循环。
如果不满足条件则执行下面的语句,一轮循环结束刚好到cond_7
,执行add-int/lit8 v5, v5, 0x4
相当于java代码中的j += 4
,然后返回goto_0
,继续判断j < height
是否成立。
.line 48
.local v2, "frameSize":I
const/4 v5, 0x0
.local v5, "j":I
const/4 v13, 0x0
.local v13, "ypd":I
:goto_0
move/from16 v0, p3
if-ge v5, v0, :cond_8
......
:cond_7
add-int/lit8 v5, v5, 0x4
goto/16 :goto_0
.line 85
.end local v4 # "i":I
.end local v7 # "u":I
.end local v9 # "uvp":I
.end local v10 # "v":I
:cond_8
return-void
第49行java代码,三个赋值语句
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
比较容易理解,其中uvp = frameSize + (j >> 1) * width
对应smali代码前三行:
.line 49
shr-int/lit8 v14, v5, 0x1
mul-int v14, v14, p2
add-int v8, v2, v14
.local v8, "uvp":I
const/4 v7, 0x0
.local v7, "u":I
const/4 v10, 0x0
在把那个加密算法逆向出来之前,应该会持续更新!
Reference
[课程]Android-CTF解题方法汇总!
最后于 2018-6-7 17:34
被Explorerl编辑
,原因: