该crackme主要实现都在so中,用ida加载libqihoo.so,出现以下错误

第一个错误说明是节区头部表格的表项大小错误,第二个错误是指节区头部表格的大小或偏移值错误。不管它,点击“Yes”继续加载。找到JNI_OnLoad函数,发现该函数已经加密:

我们知道so 文件加载时首先会查看 .init 或 .init_array 段是否存在,如果存在那么就先运行这段的内容,如果不存在的话那么就检查是否存在JNI_OnLoad,存在则执行。所以JNI_OnLoad的解密可能在 .init 或 .init_array 段中。
因为 .init 或者 .init_array 在 IDA 动态调试的时候是不会显示出来的,所以需要静态分析出这两段的偏移量然后动态调试的时候计算出绝对位置,然后在 make code(快捷键:c),这样才可以看到该段内的代码内容。
查看 .init_array 段的地址有两种办法:
(1).可以使用 IDA 加载 .so 文件,按ctrl+s快捷键查看 “Segments” 视图,这里会列出不同类型的代码段信息,如下图所示。

(2).可以使用二进制工具 readelf 来查看 .so 文件的结构,在 OS X 上面可以使用 greadelf 代替。

从上述(1)可以看出,并没有显示该so的.init 或者 .init_array段,所以我们需要对该so进行修复。
因为节区头部表的偏移值e_shoff为0x2118c(在0x20h处),所以根据ELF文件的结构,从该偏移值开始到文件结尾的数据为整个节区头部表。由于节区头部表项的大小(e_shentsize)固定为0x28,所以我们可以由:(0x214fb - 0x2118c + 1)/0x28 = 0x16 得出真正的节区头部表项数目(e_shnum)为0x16。
下面再来看e_shstrndx字段,我们从ELF文件中可以明显地看出,字符串表节区为最后一个节区,所以它的索引值应当为0x15。

根据上述规则将对应数值修改好后保存文件,然后再次加载修复后的so文件,已经不会报错了,按ctrl+s快捷键也可以查看到.init_array段信息了:

IDA 定位到.init_array段,可以看到.init_array段会执行__gnu_armfini_26函数

该函数含义大量花指令,为了便于分析,我们在该函数下断点,对其进行动态调试。通过动态调试,我们会发现该so中花指令与真实指令的关系如下图所示:

__gnu_armfini_26函数清除花指令后的汇编代码如下:

BL __gnu_armfini_30
MOV R4, R0
MOV R0, #0x28 ; '('
BL sysconf ; 获取系统的cpu个数和可用的cpu个数
ADD R1, R4, #0x8A00
BIC R0, R4, #0xFF0
MOV R2, #
ADD R1, R1, #0xEC
BIC R0, R0, #0xF
BL __gnu_arm_fini_06
MOV R1, #0x8A00
MOV R0, R4
ADD R1, R1, #0xEC
BL __gnu_armfini_29
ADD R1, R4, #0x8A00
MOV R0, R4
ADD R1, R1, #0xEC
BL sub_B6E37614

其中调用的__gnu_armfini_29函数比较可疑

_arm_aeabi_6去掉花指令后是

STMFD SP!, {R3-R8,R10,LR}
MOV R4, R0
MOV R5, R1 ;0000000C
MOV R8, R2
MOV R3, # :loc_B6EFDA74
STRB R3, [R8,R3] ;0x00 将r8开始的地址依次填充0-0x99
ADD R3, R3, # ;0+1
CMP R3, #0x100
BNE loc_B6EFDA74
MOV R3, #
MOV R6, R3
STRB R3, [R8,#0x100] ;R8+#0x100地址处的内容置0
STRB R3, [R8,#0x101] ;R8+#0x101地址处的内容置0
MOV R7, R8
ADD R10, R8, #0x100 ;R8:BEF9C6F4, R10:BEF9C7F4
MOV R0, R3 :loc_B6EFD914
LDRB R2, [R4,R0] ;r2=0x96,0xE6,0x57
LDRB R3, [R7] ;R3=0x00, R3=0xC2,0x00
ADD R0, R0, # ;r0=0x01, 0x02, 0x03
MOV R1, R5 ;R1=R5=0x0C
ADD R2, R2, R3 ;R2 = R2+R3=0xC6+0x00, R2 = R2+R3=0x96+0xC2=0x158, R2 = R2+R3=0xE6+0x00=0xE6
ADD R6, R2, R6 ;R6 = R2+R6=0xC6+0x00, R6 = R2+R6=0x158+0xC6=0x21E, R6 = R2+R6=0xE6+0x01E=0x104
AND R6, R6, #0xFF ;R6 = 0xC6, 0x01E, 0x004
LDRB R2, [R8,R6] ;r2=0x00, 0xEF, 0xE9
STRB R2, [R7],# ;STR R0,[R1], #8 将R0中的字数据写入以R1为地址的存储器 中,并将新地址R1+8写入R1。
STRB R3, [R8,R6] ;r3=0x00, 0xC2, 0x00
BL __aeabi_idivmod ;执行完后r1=r0=0x01,0x02,0x03
CMP R7, R10 ;r7=0xC2,r10=0x00
AND R0, R1, #0xFF ;r0:0x01
BNE loc_B6EFD914
LDMFD SP!, {R3-R8,R10,PC}

这实际上就是RC4算法的第一个步骤(参考:https://www.jianshu.com/p/fcfdcc3ff9d5):

/*
初始化状态向量S和临时向量T,供keyStream方法调用
*/

void initial() {
for(int i=;i<;++i){
S[i]=i;
T[i]=K[i%keylen];
}
}

_gnu_arm_message函数具有rc4算法的典型特征:

_gnu_armfini_29这个函数解密从0x75EEC6DC地址开始,大小为0x8AEC内存区域的数据,实际上是对地址为“基址0x75ED5000+0x176dc”,大小为0x8AEC的内存区域数据进行解密。

解密完毕后将该so dump下来,dump的起始地址及大小可以通过ida的Modules菜单获取:

dump脚本:

static main(void)
{
auto fp, begin, end, ptr;
fp = fopen("d:\\dump.so", "wb");
begin = 0x75ED5000;
end = begin + 0x23000;
for ( ptr = begin; ptr < end; ptr ++ )
fputc(Byte(ptr), fp);
}

按快捷键“shift+F2”打开脚本编写窗口写入上述脚本代码,点击“Run"运行该代码就可以在D盘根目录看到dump下来的so文件dump.so。

用IDA打开dump.so,定位到JNI_OnLoad函数,按“C”键,将数据转换成代码,按”F5“查看反编译的伪代码,按“Y”键修正变量类型,得到如下的代码:


我们知道RegisterNatives的函数原型是:

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)

第二个参数是JNINativeMethod结构体

typedef struct {
  const char* name;
  const char* signature;
  void* fnPtr;
} JNINativeMethod;

结构体的第三个参数是函数指针,该结构体的偏移地址为0x22004,定位到该偏移地址处发现没有正常把函数指针解析出来,需要进一步调试。


重新打开libqihoo.so,在 __gnu_armfini_29函数处下断点,进行动态调试。按F9运行到这里后,函数会进行内存区块解密,解密完成之后,在Modules菜单中找到libqihoo.so,点开,我们就可以看到“verify”和“JNI_OnLoad”函数了,分别下断点(注意,一定要在解密完之后,即执行完__gnu_arm_message函数后再下断点),如图所示:

再按F9就来到了JNI_OnLoad函数处

定位到JNINativeMethod结构体地址,从ida中我们可以看到该结构体函数指针指向verify函数:

继续F9,执行到verify函数。
在verify函数中调用了__gnu_Unwind_8和__gnu_Unwind_6函数。
__gnu_Unwind_8函数的作用是将jstring转换成为c/c++中的char*
从java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char*不同,所以如果你直接当做char*使用的话,就会出错。因此在使用之前需要将jstring转换成为c/c++中的char*,这里使用JNIEnv提供的方法转换。

/* java jstring turn to c/c++ char* */
char* jstringToChar(JNIEnv* env, jstring jstr)
{
char* pStr = NULL;
jclass jstrObj = (*env)->FindClass(env, "java/lang/String");
jstring encode = (*env)->NewStringUTF(env, "utf-8");
jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray byteArray = (jbyteArray)(*env)->CallObjectMethod(env, jstr, methodId, encode);
jsize strLen = (*env)->GetArrayLength(env, byteArray);
jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);
if (jBuf > 0)
{
pStr = (char*)malloc(strLen + 1);
if (!pStr)
{
return NULL;
}
memcpy(pStr, jBuf, strLen);
pStr[strLen] = 0;
}
env->ReleaseByteArrayElements(byteArray, jBuf, 0);
return pStr;
}

实际上上述转换的字符串就是用户输入的用户名、邮箱以及序列号。

在__gnu_Unwind_6函数中会判断用户输入的序列号长度是否为8。

调用__gnu_Unwind_1函数,此函数又有很多花指令

再次调用_gnu_armfini_29函数,通过前面的分析我们知道这是一个RC4加解密函数。

在这里实际上是取“用户名+邮箱”组成的字符串的的前四个字节进行加密,如图所示:

然后就是一个比较关键的函数__gnu_Unwind_4了

这个函数实际上是实现了SHA1加密算法,以下为该算法初始化缓冲区时的特征:

__gnu_Unwind_4将”用户名+邮箱“组成的字符串(包括前四个被RC4算法加密过的字符)进行SHA1加密后,通过__gnu_Unwind_11函数与用户输入的序列号进行对比,从而判断是否破解成功。

附:其它方法
我们重新打开一个ida,加载libqihoo.so,按快捷键“shift+F2”打开脚本编写窗口编写脚本对该内存区域进行解密。如下图所示:

这样得到的就是完全解密的so文件了。
脚本内容:

import idaapi

def rc4(data, key):
"""RC4 encryption and decryption method."""
S, j, out = list(range(256)), 0, [] for i in range(256):
j = (j + S[i] + ord(key[i % len(key)])) % 256
S[i], S[j] = S[j], S[i] i = j = 0
for ch in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
out.append(chr(ord(ch) ^ S[(S[i] + S[j]) % 256])) return "".join(out) key=idaapi.get_many_bytes(0x20434,12)
addr= 0x176dc;
data=idaapi.get_many_bytes(addr,0x8aec)
decode=rc4(data,key)
idaapi.patch_bytes(addr, decode)

样本下载地址:

链接:https://pan.baidu.com/s/1pMXryhP 密码:clun

一道360 crackme的破解的更多相关文章

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

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

  2. CrackMe破解系列第一番Acid_burn

    本文作者:gncao 楼主目前是做渗透测试的,在看一些大神的文章时,有时会看到一些关于逆向方面的知识,无奈楼主不懂逆向.但是身为搞技术的嘛,不懂就学,学不懂就再学,所以就在前些日子看了一些基础的汇编视 ...

  3. 程序破解之 API HOOK技术 z

    API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socke ...

  4. premierepro破解

    1.安装硬解 360云盘 破解教程:mac sky/破解安装说明.rtf 破解软件:mac sky/Smart Adobe CS6 Blocker v1.1.app 安装文件:mac sky/Prem ...

  5. 破解 crackme4(深入底层抓出关键算法)

    系统 : Windows xp 程序 : crackme4 程序下载地址 :http://pan.baidu.com/s/1nu452xN 要求 : 注册机编写 使用工具 : OD & IDA ...

  6. [反汇编练习] 160个CrackMe之027

    [反汇编练习] 160个CrackMe之027. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  7. [反汇编练习] 160个CrackMe之026

    [反汇编练习] 160个CrackMe之026. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  8. [反汇编练习] 160个CrackMe之025

    [反汇编练习] 160个CrackMe之025. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  9. [反汇编练习] 160个CrackMe之024

    [反汇编练习] 160个CrackMe之024. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

随机推荐

  1. jQuery 入门

    不能正常引用jQuery-2.2.4.min.js所以代码没生效 jQuery 是一个 JavaScript 函数库.jQuery 库包含以下特性: HTML 元素选取 HTML 元素操作 CSS 操 ...

  2. mysql分组查询前n条数据

    建表: CREATE TABLE hard(id INT,aa varchar(50) ,bb INT,PRIMARY key(id))insert into hard values(1,'a',9) ...

  3. 纯CSS3模拟星体旋转效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. LVS三种模式分析(超详细)

    1.DR模式:(Direct Routing)直接路由模式 DR模式的网络拓扑: DR模式的工作过程: 1.当一个client发送一个WEB请求到VIP,LVS服务器根据VIP选择对应的real-se ...

  5. 阿里云云虚拟主机安装Z-BlogPHP

    简介 在阿里云买了一个云虚拟主机,叫共享虚拟主机普惠版,6 块钱一年.本着练习上手的目的,尝试在阿里云云虚拟主机上安装Z-BlogPHP,一个个人建站的CMS 系统. 云虚拟主机网页空间为200M,M ...

  6. Java与算法之(11) - 合并排序

    天下事,合久必分,分久必合.合并排序的基本思想正是先分再合. 例如对3, 1这个数列排序,首先是分,分为3和1两个数列,然后再合并并排序.合并需要额外的辅助空间,即建立一个两个数列长度之和的空数组用于 ...

  7. Java与算法之(2) - 快速排序

    快速排序的基本思路是,每次选定数列中的一个基准数,将小于基准数的数字都放到基准数左边,大于基准数的数字都放到基准数右边.然后再分别对基准数左右的两个数列分别重复以上过程.仍以4 3 6 2 7 1 5 ...

  8. 手机termux上安装msfconsole

    大家可能因为手机没有root而不能通过deploy安装kali 我们使用termux来安装渗透工具 1.下载并安装Termux,更新软件源并升级软件包 apt update apt upgrade a ...

  9. c/s与b/s 动态网站与静态网站 (网站编码统一“UTF-8”)

    1.c/s和b/s 第一张图是b/s  可以随时随地的浏览  (在服务器增加网页就能增加功能,只要改变网页就能使用户同步更新,共享性也强,开发也简单,在广域网和局域网都能建造b/s结构,然后通过int ...

  10. Spring(一)Spring的第一滴血

    前言 开始工作了,但是一进来公司本来是做爬虫和数据分析的,但是走了一个后端的,导致我必须要去顶替他的工作.因为这个项目使用的是Spring. SpringMVC.Hibernate所以我又要去回忆一下 ...