1、apktool_2.4.1.jar--用于反编和打包apk
2、jadx-gui-1.4.5--用于查看 apk 反编译源码,方便快速导出查找
3、Linux环境安装 zipalign 、apksigner--用于对齐和重新签名
1、反编后,啥也不改,直接再打包回 apk,z4 对齐并签名后安装失败,错误原因为
提示 so 未对齐,试了很多方法一直不都行,后来验证了下发现这货根本不是so,而是 jar 文件,这一招正是为了防止反编的手段。
file libsgmain.so: Java archive data (JAR)
将重打包后的 apk 再解压开,强制 so 不压缩,然后再进行对齐和签名即可,完整指令步骤如下
最终得到的 aligned.apk 就可以成功安装
先将 apk 通过 apktool 反编出来备用,一会方便修改 smali 代码 然后在 jadx-gui 中打开 apk,打开工程后,点击文件保存将所有代码保存出来,然后 cp 到 linux 下,这样方便快速查找关键词 比如界面显示未授权的设备,可以通过 grep 未授权 ./ -nir 快速搜索到具体位置,然后在 jadx-gui 中快速定位代码位置。
1、com.a.a.a.a.a.booleanValue() 为 false 则直接忽略检查,可能是为了测试模式留的 2、为 true,则检查指定包名的apk对应的 SHA-256 签名值是否和固定值相等,一致则认为设备已授权
看到蓝牙绑定时报错 log 如下
对应代码为先获取 BluetoothManager getAdapter 通过 getAddress 方法获取 mac,
取不到则再进行反射调用,调用时抛出权限异常
Caused by: java.lang.SecurityException: Need LOCAL_MAC_ADDRESS permission: Neither user 10032 nor current process has android.permission.LOCAL_MAC_ADDRESS.
高版本安卓此权限必须是系统 app 才能拥有,可以修改 smali 代码直接走下面的 Secure 查询 bluetooth_address 即可
扫码绑定后本地开始生成付款条码
调用对应 so 生成条码
本文内容仅用于技术研究与学习交流目的,不涉及任何商业用途。 文中所提及的技术手段、工具使用及分析过程均基于开源或公开信息进行探讨,不代表鼓励或支持任何非法行为。 若您使用相关技术从事违法行为,后果自负,与本文作者无关。 如有侵权,联系删文。
反编指令
java -jar apktool_2.
4.1
.jar d .\test.apk -o test
打包指令
java -jar apktool_2.
4.1
.jar b test -o testPack.apk
反编指令
java -jar apktool_2.
4.1
.jar d .\test.apk -o test
打包指令
java -jar apktool_2.
4.1
.jar b test -o testPack.apk
D NativeLibraryHelper: Library
'libsgmain.so'
is not page-aligned - will not be able to open it directly from apk.
W NativeHelper: Failure copying
native
libraries [errorCode=-
2
]
D NativeLibraryHelper: Library
'libsgmain.so'
is not page-aligned - will not be able to open it directly from apk.
W NativeHelper: Failure copying
native
libraries [errorCode=-
2
]
java -jar apktool_2.
4.1
.jar b .\test -o unsigned.apk
然后再到 linux 环境下处理
unzip unsigned.apk -d apk_unpacked/
cd apk_unpacked/
zip -r -
0
../repack-unsigned.apk *
zipalign -f -v -p
4
repack-unsigned.apk aligned.apk
apksigner sign --ks test.jks --ks-key-alias xxxx -ks-pass pass:xxxx ./aligned.apk
java -jar apktool_2.
4.1
.jar b .\test -o unsigned.apk
然后再到 linux 环境下处理
unzip unsigned.apk -d apk_unpacked/
cd apk_unpacked/
zip -r -
0
../repack-unsigned.apk *
zipalign -f -v -p
4
repack-unsigned.apk aligned.apk
apksigner sign --ks test.jks --ks-key-alias xxxx -ks-pass pass:xxxx ./aligned.apk
private
void
c() {
if
(com.xpay.watch.utils.a.a(
this
)) {
getWindow().addFlags(
128
);
setContentView(com.xpay.watch.utils.g.a(
this
, R.layout.activity_watch_main));
com.xpay.android.watchsdk.g.a().g();
if
(!com.xpay.android.watchsdk.l.a().e()) {
com.xpay.android.watchsdk.g.a().a(com.xpay.watch.utils.h.a(), com.xpay.watch.utils.h.b(),
null
);
try
{
com.xpay.android.watchsdk.ble.d.a().f();
}
catch
(Throwable th) {
com.xpay.android.phone.inside.log.api.b.a(th);
}
this
.a.postDelayed(
this
.h, 200L);
com.xpay.android.watchsdk.l.a().l();
}
else
{
d();
this
.a.postDelayed(
this
.i, 200L);
}
}
else
{
DialogUtil.a aVar =
new
DialogUtil.a(
this
);
aVar.a(DialogUtil.DialogType.SINGLE_BUTTON);
aVar.a(getString(R.string.dlg_authorization_check_failed_title));
aVar.b(getString(R.string.dlg_authorization_check_failed_tips));
aVar.c(
"c-"
+ com.xpay.watch.utils.h.a() +
" m-"
+ Build.MODEL);
aVar.a(
new
h(
this
));
DialogUtil.a(aVar);
}
public
static
boolean
a(Context context) {
if
(com.a.a.a.a.a.booleanValue()) {
String[] split = h.f().split(
","
);
String[] split2 = h.e().split(
","
);
if
(split2 ==
null
|| split2.length <=
0
) {
return
false
;
}
for
(
int
i =
0
; i < split2.length; i++) {
Log.w(
"xpay_watch"
,
"packageName |"
+ split2[i]);
if
(a(context, split2[i], split)) {
return
true
;
}
}
return
false
;
}
return
true
;
}
private
static
boolean
a(Context context, String str, String[] strArr) {
List<String> a2 = a(context, str);
if
(a2 ==
null
|| a2.size() <=
0
) {
return
false
;
}
for
(String str2 : strArr) {
String trim = str2.trim();
Log.w(
"xpay_watch"
, str +
" "
+ a2.get(
0
).toUpperCase() + trim.toUpperCase());
if
(TextUtils.equals(a2.get(
0
).toUpperCase(), trim.toUpperCase())) {
return
true
;
}
}
return
false
;
}
private
static
List<String> a(Context context, String str) {
try
{
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(str,
64
);
if
(packageInfo !=
null
) {
Signature[] signatureArr = packageInfo.signatures;
MessageDigest messageDigest = MessageDigest.getInstance(
"SHA-256"
);
ArrayList arrayList =
new
ArrayList();
for
(Signature signature : signatureArr) {
byte
[] digest = messageDigest.digest(signature.toByteArray());
StringBuilder sb =
new
StringBuilder((digest.length *
3
) -
1
);
int
length = digest.length -
1
;
for
(
int
i =
0
; i <= length; i++) {
byte
b = digest[i];
sb.append(a[(b &
240
) >>
4
]);
sb.append(a[b &
15
]);
if
(i < length) {
sb.append(
':'
);
}
}
String sb2 = sb.toString();
arrayList.add(sb2);
com.xpay.android.phone.inside.log.api.b.a(
"package |"
+ str +
"| fingerprint: "
+ sb2);
Log.w(
"xpay_watch"
,
"package |"
+ str +
"| fingerprint: "
+ sb2);
}
return
arrayList;
}
return
null
;
}
catch
(Throwable th) {
th.printStackTrace();
return
null
;
}
}
private
void
c() {
if
(com.xpay.watch.utils.a.a(
this
)) {
getWindow().addFlags(
128
);
setContentView(com.xpay.watch.utils.g.a(
this
, R.layout.activity_watch_main));
com.xpay.android.watchsdk.g.a().g();
if
(!com.xpay.android.watchsdk.l.a().e()) {
com.xpay.android.watchsdk.g.a().a(com.xpay.watch.utils.h.a(), com.xpay.watch.utils.h.b(),
null
);
try
{
com.xpay.android.watchsdk.ble.d.a().f();
}
catch
(Throwable th) {
com.xpay.android.phone.inside.log.api.b.a(th);
}
this
.a.postDelayed(
this
.h, 200L);
com.xpay.android.watchsdk.l.a().l();
}
else
{
d();
this
.a.postDelayed(
this
.i, 200L);
}
}
else
{
DialogUtil.a aVar =
new
DialogUtil.a(
this
);
aVar.a(DialogUtil.DialogType.SINGLE_BUTTON);
aVar.a(getString(R.string.dlg_authorization_check_failed_title));
aVar.b(getString(R.string.dlg_authorization_check_failed_tips));
aVar.c(
"c-"
+ com.xpay.watch.utils.h.a() +
" m-"
+ Build.MODEL);
aVar.a(
new
h(
this
));
DialogUtil.a(aVar);
}
public
static
boolean
a(Context context) {
if
(com.a.a.a.a.a.booleanValue()) {
String[] split = h.f().split(
","
);
String[] split2 = h.e().split(
","
);
if
(split2 ==
null
|| split2.length <=
0
) {
return
false
;
}
for
(
int
i =
0
; i < split2.length; i++) {
Log.w(
"xpay_watch"
,
"packageName |"
+ split2[i]);
if
(a(context, split2[i], split)) {
return
true
;
}
}
return
false
;
}
return
true
;
}
private
static
boolean
a(Context context, String str, String[] strArr) {
List<String> a2 = a(context, str);
if
(a2 ==
null
|| a2.size() <=
0
) {
return
false
;
}
for
(String str2 : strArr) {
String trim = str2.trim();
Log.w(
"xpay_watch"
, str +
" "
+ a2.get(
0
).toUpperCase() + trim.toUpperCase());
if
(TextUtils.equals(a2.get(
0
).toUpperCase(), trim.toUpperCase())) {
return
true
;
}
}
return
false
;
}
private
static
List<String> a(Context context, String str) {
try
{
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(str,
64
);
if
(packageInfo !=
null
) {
Signature[] signatureArr = packageInfo.signatures;
MessageDigest messageDigest = MessageDigest.getInstance(
"SHA-256"
);
ArrayList arrayList =
new
ArrayList();
for
(Signature signature : signatureArr) {
byte
[] digest = messageDigest.digest(signature.toByteArray());
StringBuilder sb =
new
StringBuilder((digest.length *
3
) -
1
);
int
length = digest.length -
1
;
for
(
int
i =
0
; i <= length; i++) {
byte
b = digest[i];
sb.append(a[(b &
240
) >>
4
]);
sb.append(a[b &
15
]);
if
(i < length) {
sb.append(
':'
);
}
}
String sb2 = sb.toString();
arrayList.add(sb2);
com.xpay.android.phone.inside.log.api.b.a(
"package |"
+ str +
"| fingerprint: "
+ sb2);
Log.w(
"xpay_watch"
,
"package |"
+ str +
"| fingerprint: "
+ sb2);
}
return
arrayList;
}
return
null
;
}
catch
(Throwable th) {
th.printStackTrace();
return
null
;
}
}
14
:
05
:
57.870
9853
BluetoothGattServer D onServiceAdded() - handle=
40
uuid=
00003802
-
0000
-
1000
-
8000
-00805f9b34fb status=
0
14
:
05
:
57.874
9853
BluetoothGattServer W Unhandled exception in callback
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String java.lang.String.toUpperCase()'
on a
null
object reference
at com.xpay.android.watchsdk.ble.d.b(SourceFile:
542
)
at com.xpay.android.watchsdk.ble.d.a(SourceFile:
44
)
at com.xpay.android.watchsdk.ble.d$a.onServiceAdded(SourceFile:
441
)
at android.bluetooth.BluetoothGattServer$
1
.onServiceAdded(BluetoothGattServer.java:
136
)
at android.bluetooth.IBluetoothGattServerCallback$Stub.onTransact(IBluetoothGattServerCallback.java:
85
)
at android.os.Binder.execTransact(Binder.java:
723
)
14
:
06
:
13.725
9853
zygote I Debugger is no longer active
14
:
05
:
57.870
9853
BluetoothGattServer D onServiceAdded() - handle=
40
uuid=
00003802
-
0000
-
1000
-
8000
-00805f9b34fb status=
0
14
:
05
:
57.874
9853
BluetoothGattServer W Unhandled exception in callback
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String java.lang.String.toUpperCase()'
on a
null
object reference
at com.xpay.android.watchsdk.ble.d.b(SourceFile:
542
)
at com.xpay.android.watchsdk.ble.d.a(SourceFile:
44
)
at com.xpay.android.watchsdk.ble.d$a.onServiceAdded(SourceFile:
441
)
at android.bluetooth.BluetoothGattServer$
1
.onServiceAdded(BluetoothGattServer.java:
136
)
at android.bluetooth.IBluetoothGattServerCallback$Stub.onTransact(IBluetoothGattServerCallback.java:
85
)
at android.os.Binder.execTransact(Binder.java:
723
)
14
:
06
:
13.725
9853
zygote I Debugger is no longer active
public
String b() {
if
(
this
.k ==
null
) {
if
(
this
.h ==
null
) {
this
.h = (BluetoothManager)
this
.c.getSystemService(
"bluetooth"
);
if
(
this
.h ==
null
) {
com.xpay.android.phone.inside.log.api.b.b(
"Unable to initialize BluetoothManager."
);
return
null
;
}
}
this
.i =
this
.h.getAdapter();
if
(
this
.i ==
null
) {
com.xpay.android.phone.inside.log.api.b.b(
"Unable to obtain a BluetoothAdapter."
);
return
null
;
}
this
.k =
this
.i.getAddress();
if
(TextUtils.isEmpty(
this
.k) ||
this
.k.endsWith(
"00:00:00:00:00"
)) {
try
{
this
.k = a(
this
.i);
}
catch
(Throwable th) {
com.xpay.android.phone.inside.log.api.b.a(th);
}
}
if
(TextUtils.isEmpty(
this
.k) ||
this
.k.endsWith(
"00:00:00:00:00"
)) {
try
{
this
.k = Settings.Secure.getString(
this
.c.getContentResolver(),
"bluetooth_address"
);
}
catch
(Throwable th2) {
com.xpay.android.phone.inside.log.api.b.a(th2);
}
}
com.xpay.android.phone.inside.log.api.b.a(
"ServerAddress:"
+
this
.k);
}
return
this
.k;
}
private
static
String a(BluetoothAdapter bluetoothAdapter) {
Object obj;
try
{
Field declaredField = BluetoothAdapter.
class
.getDeclaredField(
"mService"
);
declaredField.setAccessible(
true
);
obj = declaredField.get(bluetoothAdapter);
}
catch
(Throwable th) {
com.xpay.android.phone.inside.log.api.b.a(th);
}
if
(obj ==
null
) {
return
null
;
}
Method declaredMethod = obj.getClass().getDeclaredMethod(
"getAddress"
,
new
Class[
0
]);
declaredMethod.setAccessible(
true
);
Object invoke = declaredMethod.invoke(obj,
new
Object[
0
]);
if
(invoke !=
null
&& (invoke
instanceof
String)) {
return
(String) invoke;
}
return
null
;
}
public
String b() {
if
(
this
.k ==
null
) {
if
(
this
.h ==
null
) {
this
.h = (BluetoothManager)
this
.c.getSystemService(
"bluetooth"
);
if
(
this
.h ==
null
) {
com.xpay.android.phone.inside.log.api.b.b(
"Unable to initialize BluetoothManager."
);
return
null
;
[培训]科锐逆向工程师培训第53期2025年7月8日开班!