1. apk安装到手机,一样的界面,随便输入一样的报错

2. apk拖入到jadx重看看

public native String sha1(String str);

    static {
System.loadLibrary("native-lib");
} /* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
initViews();
} private void initViews() {
this.edt_code = (EditText) findViewById(R.id.edt_code);
this.edt_username = (EditText) findViewById(R.id.edt_username);
Button button = (Button) findViewById(R.id.btn_register);
this.btn_register = button;
button.setOnClickListener(new View.OnClickListener() { // from class: com.r0ysue.sha1.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
String obj = MainActivity.this.edt_username.getText().toString();
if (MainActivity.this.sha1(obj).equals(MainActivity.this.edt_code.getText().toString())) {
Toast.makeText(MainActivity.this, "SUCCESS!", 0).show();
} else {
Toast.makeText(MainActivity.this, "ERROR!", 0).show();
}
}
});
}

和第一题的套路一样,native方法名换成了sha1

3. 导出so,放入IDA中进行分析

jstring __fastcall Java_com_r0ysue_sha1_MainActivity_sha1(JNIEnv *env, jobject object, void *str)
{
char *v4; // x20
__int64 v5; // x23
char *v6; // x20
char v8[44]; // [xsp+4h] [xbp-7Ch] BYREF
char v9[24]; // [xsp+30h] [xbp-50h] BYREF
__int64 v10; // [xsp+48h] [xbp-38h] v10 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
v4 = (char *)(*env)->GetStringUTFChars(env, str, 0LL);
strlen(v4);
sub_1BC0((int)v9, v4);
v5 = 0LL;
v6 = v8;
do
{
sub_7E8(v6, -1LL);
++v5;
v6 += 2;
}
while ( v5 != 20 );
return (*env)->NewStringUTF(env, v8);
}

进入sub_1BC0中看看

__int64 __fastcall sub_1BC0(int a1, void *a2)
{
__int128 v4; // [xsp+0h] [xbp-80h] BYREF
__int64 v5; // [xsp+10h] [xbp-70h]
int v6; // [xsp+18h] [xbp-68h]
__int64 v7; // [xsp+68h] [xbp-18h] v7 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
v4 = xmmword_1C50;
v5 = 0xC3D2E1F0LL;
v6 = 0;
sub_19F0((int)&v4, a2);
return sub_1AD4(a1, (int)&v4);
}

这个0xC3D2E1F0很眼熟,查了一些果然是sha1的特征初始化常量之一

sha1 初始化常量
A = 0x67452301
B = 0xEFCDAB89
C = 0x98BADCFE
D = 0x10325476
E = 0xC3D2E1F0 sha1 常量K
K = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6]
0≤t≤19 K = 0x5A827999
20≤t≤39 K = 0x6ED9EBA1
40≤t≤59 K = 0x8F1BBCDC
60≤t≤79 K = 0xCA62C1D6

既然已经找到了第一个,看看xmmword_1C50 会不会有所发现

0000000000001C50  01 23 45 67 89 AB CD EF  FE CC BA 98 76 54 32 10  .#Eg........vT2.

可以看到 这个数组对应的值,正好就是另外这个初始化变量的值(小端展示,需倒着看)

但是注意到有一个值是对应不上的 FE CC BA 98 76这里故意是将DC改成了CC, 所以相信直接用标准的Sha1算法计算出来的值,和这里的sha1算出来的值绝对是不一样的;

而在后续sub_19F0方法中我们找到了所有的K值,说明K是没有被魔改的

4. 编写frida看看,返回值是多少

function main() {
Java.perform(function () { var MainActivityHandler = Java.use('com.r0ysue.sha1.MainActivity') console.log('1111')
if (MainActivityHandler != undefined) {
console.log('2222' )
MainActivityHandler.sha1.implementation = function (str) {
console.log('hooked src str = ' + str)
var ret = this.sha1(str)
console.log('hooked ret = ' + ret) return ret
}
} }) } setTimeout(main, 1000)

日志

2222
hooked src str = abcd
hooked ret = 84fa69e00c65b500653e402ab42f9a2f26daa02c

通过在线sha1计算后的值是81fe8bfe87576c3ecb22426f8e57847382917acf

果然如我们所料,两个sha1的结果不一致

5. 编写python注册机,通过修改初始化常量值来匹配试试

#初始化变量
K = [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6] A = 0x67452301
B = 0xEFCDAB89
C = 0x98BACCFE
D = 0x10325476
E = 0xC3D2E1F0 A0 = 0x67452301
B0 = 0xEFCDAB89
C0 = 0x98BACCFE
D0 = 0x10325476
E0 = 0xC3D2E1F0 '''字节转换,字节(8bit)->字(32bit)'''
def CharToWord( context,i):
return ((ord(context[i]) & 0x000000ff) << 24) | ((ord(context[i + 1]) & 0x000000ff) << 16) | ((ord(context[i + 2]) & 0x000000ff) << 8) | (ord(context[i + 3]) & 0x000000ff) '''填充补位获得原始明文'''
def SHA1_fill(plaintext, group, length):
print("补位后的明文:")
text1 = list(plaintext)
for n in range(length//8, 56):
text1.append(chr(0))
plaintext=''.join(text1)
temp = length // 32
len1 = length
while len1 > 0:
len1 = len1//32
if len1:
for j in range(0, temp):
group[j] = CharToWord(plaintext, 4 * j)
print(hex(group[j]))
else:
text = list(plaintext)
b = 0x80
text.insert(length // 8, chr(b))
plaintext = ''.join(text)
group[temp] = CharToWord(plaintext, temp * 4)
print(hex(group[temp]))
break
group[15] = length
for i in range(temp + 1,16):
print(hex(group[i]).ljust(10, '0')) '''f函数'''
def f(B ,C ,D , t):
if t >=0 and t <= 19:
return (B & C) ^ (~B & D)
if t >= 20 and t <= 39:
return B ^ C ^ D
if t >= 40 and t <= 59:
return (B & C) ^ (B & D) ^ (C & D)
if t >= 60 and t <= 79:
return B ^ C ^ D '''获得 Kt'''
def GETK(t):
if t >= 0 and t <= 19:
return K[0]
if t >= 20 and t <= 39:
return K[1]
if t >= 40 and t <= 59:
return K[2]
if t >= 60 and t <= 79:
return K[3] '''获得 Wt ,这里要特别注意mod(2**32)'''
def GETW(w):
for i in range(16,80):
w[i] = (((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) | ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31)) % 2**32 '''步函数,注意mod(2**32)'''
def Step(t,w):
global A
global B
global C
global D
global E
T = (((A << 5) | (A >> 27)) + f(B, C, D, t) + E + w[t] + GETK(t)) % 2**32
E = D
D = C
C = ((B << 30) | (B >> 2)) % 2**32
B = A
A = T '''获得密文'''
def GetCipher(cipher):
cipher[0] = (A0 + A) % 2**32
cipher[1] = (B0 + B) % 2**32
cipher[2] = (C0 + C) % 2**32
cipher[3] = (D0 + D) % 2**32
cipher[4] = (E0 + E) % 2**32
print("密文为:")
for j in range(0, 5):
print(hex(cipher[j])[2:], end='')
print() def SHA1(context, cipher):
len1 = len(context) * 8
group = []
for i in range(80):
group.append(0)
SHA1_fill(context, group, len1)
GETW(group)
for t in range(80):
Step(t, group)
GetCipher(cipher) m = input("请输入长度小于56的明文:")
c = []
for i in range(0, 5):
c.append(0)
SHA1(m, c)
'''以下为python自带sha1函数,以便对照'''
import hashlib
print("自带函数哈希后密文:")
b = hashlib.sha1()
b.update(m.encode())
sha1 = b.hexdigest()
print(sha1)

日志

密文为:
84fa69e0c65b500653e402ab42f9a2f26daa02c
自带函数哈希后密文:
81fe8bfe87576c3ecb22426f8e57847382917acf

ok,成功对上,输入到手机爆破成功

【Android逆向】破解看雪9月算法破解第二题的更多相关文章

  1. off-by-one&doublefree. 看雪10月ctf2017 TSRC 第四题赛后学习

    off-by-one 0x00 发现漏洞 1.off-by-one 在massage函数中,如图所示,可以修改的字节数比原内存大小多了一个字节 2.悬挂指针 可以看到,在free堆块的时候,没有清空指 ...

  2. Android逆向之so的半自动化逆向

    因为工作需要,转型干android逆向,有几个月了.不过对于so的逆向,任然停留在,难难难的阶段,虽然上次自己还是逆向了一个15k左右的小so文件,但是,那个基本是靠,一步一步跟代码,查看堆栈信息来自 ...

  3. 天眼查sign 算法破解

    天眼查sign 算法破解 最近真的在sign算法破解上一去不复返 前几天看过了企查查的sign破解 今天再看看天眼查的sign算法破解,说的好(zhuang)点(bi)就是破解,不好的就是这是很简单的 ...

  4. Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)

    Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码) 来源 https://blog.csdn.net/jiangwei0910410003/article/details/51 ...

  5. Android 逆向实战篇(加密数据包破解)

    1. 实战背景由于工作需要,要爬取某款App的数据,App的具体名称此处不便透露,避免他们发现并修改加密逻辑我就得重新破解了. 爬取这款App时发现,抓包抓到的数据是加密过的,如图1所示(原数据较长, ...

  6. 看雪论坛 破解exe 看雪CTF2017第一题分析-『CrackMe』-看雪安全论坛

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 逆向 黑客 破解 学习 论坛 『CrackMe』 http://bbs.pediy.co ...

  7. 启xin宝app的token算法破解——逆向篇(二)

    启xin宝app的token算法破解--抓包分析篇(一)文章已经对该app进行了抓包分析,现在继续对它进行逆向. 对于一个app而言,我们要逆向app,需要知道什么呢? 逆向工具 Java基础,甚至c ...

  8. Android逆向——破解水果大战

    最近公司需要测试安卓app安全,但安卓基本上0基础,决定开始学习下安卓逆向根据吾爱破解上教程 <教我兄弟学Android逆向系列课程+附件导航帖> https://www.52pojie. ...

  9. Android逆向破解表单注册程序

    Android逆向破解表单注册程序 Android开发 ADT: android studio(as) 程序界面如下,注册码为6位随机数字,注册成功时弹出通知注册成功,注册失败时弹出通知注册失败. 布 ...

  10. Android逆向破解表单登录程序

    Android逆向破解表单登录程序 Android开发 ADT: android studio(as) 程序界面如下,登录成功时弹出通知登录成功,登录失败时弹出通知登录失败. 布局代码 <?xm ...

随机推荐

  1. [转帖]使用 BR 命令行备份恢复

    TiDB试用 来源:TiDB  浏览 404 扫码 分享 2021-04-20 20:49:42 使用 BR 命令行进行备份恢复 BR 命令行描述 命令和子命令 常用选项 使用 BR 命令行备份集群数 ...

  2. [转帖]Linux之pure-ftpd安装和使用

    一.pure-ftpd简介   PureFTPd是一款专注于程序健壮和软件安全的免费FTP服务器软件(基于BSD License),以安全和配置简单为设计目标,支持虚拟主机,IPV6,PAM等功能.. ...

  3. [转帖]Linux下在文件内部指定行(首行、末尾行等)插入内容

    https://blog.csdn.net/drbing/article/details/52153766 1.在文件的首行插入指定内容: :~$ sed -i "1i#! /bin/sh ...

  4. [转帖]45个处理字符串的Python方法

    https://baijiahao.baidu.com/s?id=1738413163267646541&wfr=spider&for=pc   一.题目解析 先来看一个题目: 判断用 ...

  5. Win10 查看无线局域网的密码

    1. 打开命令行 输入 control 打开控制面板 2. 进入网络和共享中心 3. 打开连接 4. 使用如下进行查看.

  6. Docker 完整指南

    欢迎来到 Docker 的完整指南!在这个教程中,我们将深入研究 Docker 的各种特性,从基础的容器操作到高级的网络配置和数据管理.让我们一步步地探索 Docker 的丰富功能. 1. 安装 Do ...

  7. 不同版本的Unity要求的NDK版本和两者对应关系表(Unity NDK Version Match)

    IL2CPP需要NDK Unity使用IL2CPP模式出安卓包时,需要用到NDK,如果没有安装则无法导出Android Studio工程或直接生成APK,本篇记录一下我下载NDK不同版本的填坑过程. ...

  8. 【五】AI Studio 项目详解【VisualDL工具、环境使用说明、脚本任务、图形化任务、(五)在线部署及预测】PARL

    相关文章 [一]-环境配置+python入门教学 [二]-Parl基础命令 [三]-Notebook.&pdb.ipdb 调试 [四]-强化学习入门简介 [五]-Sarsa&Qlear ...

  9. C/C++ Qt 常用数据结构

    Qt 是一个跨平台的图形化类库,常用数据结构就是对C++ STL的二次封装,使其更加易用,如下是经常会用到的一些数据结构和算法,其中包括了QString,QList,QLinkedList,QVect ...

  10. C/C++ BeaEngine 反汇编引擎

    反汇编引擎有很多,这个引擎没有Dll,是纯静态链接库,适合r3-r0环境,你可以将其编译为DLL文件,驱动强制注入到游戏进程中,让其快速反汇编,读取出反汇编代码并保存为txt文本,本地分析. 地址:h ...