首页
社区
课程
招聘
[原创] KCTF 2020 Win. 第四题 路在何方
发表于: 2020-11-24 12:18 4856

[原创] KCTF 2020 Win. 第四题 路在何方

HHHso 活跃值
22
2020-11-24 12:18
4856

庚子年十月初八,小雪,贞曰:宜坏垣(拆除围墙)。

摘要:这是一条几乎全静态的分析之路,部分片段使用了Unicorn模拟执行。最后有上机的操作,是在最后一步自陷后,投石问路之举。目的是捕捉下特定时态的内存空间,拍个照,以印证静态分析走过的路是否正确,能否继续走下去。分析都是以第一个加固版本为样本【App_Crackme.apk】。

两个版本样本【App_Crackme.apk】和【disanti.apk】参考文后附件。

一、初次见面
(1)7z x App_Crackme.apk -oApp_Crackme
(2)App_Crackme.apk 直接上JEB,如图。

我们通过(1)的7z.exe命令行压缩工具,将apk当zip解压到App_Crackme目录,以备用。通过(2)直接上了手头的JEB。题外,按以前的套路,(1)过后会直接将App_Crackme目录的class.dex上IDA分析;或者通过ApkToolkit.exe将apk转换为jar后上jdgui.exe查看,或者apk直接拖进jadxgui.exe也行(应注意到与前面的jdgui.exe不是同一个东西)。

大概浏览下apk的目录树,这时候注意到目录树中一些so库,这时候,
(3)可以将感兴趣的放IDA分析,如libcrack.so和libjaigu_x86.so,如图。
so在IDA自动分析完后,首先关注的肯定是敏感的到处函数,如JIN_OnLoad和java_com*这些,我们也注意到一些decode**类的函数。
概览后做了一些防护,一时间没法得到太多有用信息,先回去看看java或smali层。
图片描述

图片描述

二、绳头
从Mainifest中我们找到绳头"com.stub.StubApp"启动类,如图。
最开始JEB并不会对反编译对象做任何改动,所以类或成员以及方法都是一些不可见字节内容。这样会非常影响阅读和交叉引用查阅,我们可以右键选择rename all自动全部做初步人性化命名。让后根据StupApp类的构造函数和一些关键函数,随类方法和成员做基本重命名。

题外,IDA自身并不带自动重命名,这点比JEB弱很多,估计得找或自行写脚本重命名。

图片描述

图片描述

图片描述

AppStub的OnCreate没什么重要信息,如图。

图片描述

在AppStub相关构造函数中,我们知晓了AppStup的基本结构。

图片描述

我们在AppStub非混淆的方法中,注意到attachBaseContext(Context)方法,如图。
图片描述

其中clsUtils->decrypt_str是逆向后根据起意义重新在jeb自动命名后修正的伪类名和方法。通过逆向可以看到"decrypt_str"类方法是对一类加密字符解密操作,所以做出此命名,如
"q~tb\u007Fyt>s\u007F~du~d>`}>@qs{qwu@qbcub4@qs{qwu"
算法也简单,只是对字符异或0x10,python的解密实现如下。

我们也对clsUtils的其他方法功能做了初步分析,都是写功能性的方法,
其也在util包中,所以如此命名,其他方法如:
(1)make_p0_close(Closeable);传入文件等一类具有.close()的可关闭对象,关闭对象。
(2)IsSupported_x86();是否支持x86。
(3)cmp_bis(BufferedInputStream, BufferedInputStream)Z;对比文件流,用于比对文件。
(4)cmp_copy__assetsFilename_to_dir_filename(Context, String, String, String);迁移文件等操作,用来搬动所需so等文件。
图片描述

图片描述

attachBaseContext加载加固相关的so后,转入了so地方方法中
.method public static native interface5(Application)V
而加固相关的so又是自藏式的,如果还有一条路走到黑,就只能网jiagu.so的JNI_OnLoad等方法硬干了。否则,至此,java或smali层已经没太多信息,静态之路变得不好走了,如何是好?

图片描述

三、遇事不决,量子力学
量子力学?开个玩笑。我们还是继续看看其他什么角落又什么发现。翻箱倒柜,Certificate,.appkey,Resource下的一堆有瞄过,发现有个奇怪的【b.txt】,不得不说,JEB在自动识别上还是很人性化。直接双击就自动识别打开了,惊不惊喜,意不意外?
图片描述
(1)直接点开了check,如图。
当然,正常还是得按套路,从MainActivity开始。
题外,有试过在手上的Mate 30 Pro安装运行,结果如图。
虽然运行不起来,但还是注意到了CHECK这些。
图片描述

check的在JEB的smali视图中也还算清晰
(1)key长度为16
(2)ek = crypt(key)
(3)ck = com.kanxue.crackme.MyCrack.crackjni(ek)
(4)eck = crypt(ck)
(5)rk = base64.b64encode(eck)
(6) crk = com.kanxue.crackme.MyCrack.crypt
bOK = (rk== crk? crk:"test")

图片描述

至此,基本任务需要分别拿下crypt和crackjni方法还有MyCrack.crypt成员。JEB的crypt方法smalic基本看一下有点像RC41。用ApkToolkit将b.txt (重命名为b.dex)转换为jar用jdgui打开,如图
图片描述

题外:到此,实际上如果一开始直接将【App_Crackme.apk】仍经jadx-gui.exe;完全没有那么什么量子力学什么事,jadx-gui.exe直接一杆到底,自动识别了b.txt,并合并到类代码中,且可以对比看到,jdgui对0x100还不大友好,jadx-gui.exe比较完美还原,如图。
图片描述

题外:关于crypt方法,只看到samli的时候,直接推定了为RC41(也的确是真的RC41),因为没有动态调试,暂时也没想到直接测试反编译的java代码。所以放一边了,只知道这就算是改版的RC41,至少问题有解。就先看crackjni方法。实际上,眼见不一定为实,这时候一只脚已经踩坑里,尤其当你觉得一个真的RC41是假的时候,而真假似乎都对不上时,"你可能开始怀疑人生"。

(2)crackjni
在IDA中,我们直接定位libcrack.so的导出函Java_com_kanxue_crackme_MyCrack_crackjni,如图
图片描述

密密麻麻一堆,且IDA的字符串信息几乎没有有价值的信息。
事实上前期的探查中,我们注意到decode一类的导出函数的业务逻辑相对简单,就是对全局静态内容的异或操作,可知是加解密操作,通过观察,我们发现其都是用字节串最后一个字节作为异或因子,因此,我们可以直接解密字节内容看看。通过采样解密,确定是字符串一类。全部解密如下,

我们注意到 ('1F21B', "'crypt'"),也注意到一些base64字符串如,
('1F250', "'l+x7fKd2FBaaEY4NV4309A==\n'")
('1F270', "'ZmxhZ3RyeWFnYWluP30='")
当然还有我们在不支持运行手机上执行的提示
('1F290', "'only support Android 7,Android 7.1,Android 8,Android 8.1,Android 9'")
注意到('1F105', "'frida'")大概猜测到要反这类插桩的功能组件了。我们静态分析,可以先忽略。其中('1F21B', "'crypt'")的交叉引用到Java_com_kanxue_crackme_MyCrack_crackjni,我们跟进查看。逻辑相对也清晰 FindClass、GetStaticFieldID、NewStringUTF的逆向原理来自JNIEnv*结构,其是接口虚函数,根据偏移量可以确定函数名称。
图片描述
图片描述

(A)图中下半部分与crypt相关的就是com.kanxue.crackme.MyCrack.crypt="l+x7fKd2FBaaEY4NV4309A==\n"
本想解决crackjni,反而先解决了.MyCrack.crypt的值。
(B)图中上半部分,由于一开始没有逆向确定Hi_dex_for_mprotect的含义,所以无法确定其意义。实际这是挽救前面掉进坑的那只脚的关键。到这里先放一放,本来也没太在意这一部分,毕竟防护加固,涉及写内存修改难免。

在crackjni大概的浏览分析中,基本确定了只有部分有效代码,如下图方框所示,而几个间隔的循环材猜测是反调试一类操作。crackjni入口处,通过定位ek的交叉引用,我们得到了crackjni对ek运输的核心处理函数Hi_core_func_ek_ck_rk,如图
图片描述
图片描述
图片描述
Hi_core_func_ek_ck_rk函数业务逻辑比较清楚
其中ek是crackjni输入,ck是内置的"kaokaonikaokaoni",rk为处理结果。
(1)rk=ek;k初始为ek值,
(2)Hi_stepA_gen_xtbl_from_pck;通过ck,生产xtbl表
(3)Hi_stepB;通过xtbl表和内置的sbox表等对rk进行变换。
图片描述
图片描述
其中(2)中的Hi_stepA_gen_xtbl_from_pck没用到ek,而只用到内置固定的ck和固定的sbox表和Hi_Noekeon表。
如图, Hi_sbox_at只是对sbox表的索引[idx]。
图片描述

其中(3)StepB对rk进行主要的变换,我们需要根据变换业务逻辑得到逆变换
StepB如图,业务逻辑也比较清晰,其中关键的几个变换函数如下
(3.1)Hi_prk_xor_xtbl_R0_A10h_X,使用xtbl中第X行矩阵与rk异或,xtbl有11行,每行16个字节,rk也是16个字节矩阵,变换可逆。
(3.2)Hi_sbox_map,使用sbox表对rk进行索引变换,即rk[i]=sbox[rk[i]],i=0...15,变换可逆。
(3.3)Hi_rxbhgd对rk内部16字节顺序进行交换,变换可逆。
(3.4)Hi_cbx对rk分段(没四个字节一段)进行变换,半可逆。
可见,要完成逆变换,关键是(2)中的xtbl,sbox表以及(3)中的各个变换的逆变换
图片描述

四、正负变换
(4.1)获取xtbl,sbox
(4.2)各正逆变换

IDA分析中发现,Hi_core_func_ek_ck_rk函数层级调用全是纯内调的shellcode(内有对系统api调用)。所以用unicorn简单配置即可模拟执行,不需要任何额外劫持解析。如图,初始化ek,ck,rk的指针,然后从0xC2B8运行到Step停止,然后我们读取xtbl的值(也读取sbox)备用。
图片描述

其中关键还是(3.4)的cbx半可逆变换。这里称cbx为16字节Noekeon变换,其只是是分段完成,关键是4字节Noekeon变换;之所以称为Noekeon,是在xtbl生成中用到Noekeon表,为啥又称Noekeon表,因为在用表中的常量google时,其结果展示Noekeon算法,而4字节Noekeon变换与Noekeon算法又相似之处,虽然未证明其关系如何,姑且成为Noekeon变换。这里的之所以说半可逆,可能时能力有限,未找到高效的完全可逆算法,这里四个字节,相互限制,一个确定,则可以推定另一个,是一个闭环证明。及4字节只有256中情形,
所以可以遍历的方式进行逆变换。

五、出路

各正逆变换都是测试过多,大体逻辑应该也不会有问题。在排查各正逆变换没问题后,最终还是回到了前述crackjni对crypt属性设置的代码前面部分片段
图片描述
如图,这一部分意思可以看出 Hi_dex_for_mprotect 放的是一个指针,
其对指针Hi_dex_for_mprotect偏移0x16D3A6位置修改为 0xD3,0x3D,那么Hi_dex_for_mprotect是啥?静态分析并不能得到快速确定,我们看下Hi_dex_for_mprotect的交叉引用,尝试确定其赋值位置。
如图,有几处都是赋值位置,我们看下第一处。
图片描述
图片描述
在第一处赋值位置,我们看到其值来自于局部变量lv_30_src_ptr.04hww,
其也作为mprotect函数的地址addr参数,结果PROT_WIRTE,我们就更确定是为后面的内存修改铺垫了。同时主要到lv_30_src_ptr.04hww也即Hi_dex_for_mprotect的长度是lv_30_src_ptr.08hww。
在mprotect修改前,lv_30_src_ptr.08hww长度len与0x281CB8比较,必须小于它,可见目标内存长度原则上不超过0x281CB8,突破口源自对整个数字的敏感。因为前面用7z解压出的b.txt大小就是2MB左右,会不会就是它?这只是猜测,我们用python的相关函数获取了b.txt的字节大小,

发现就是0x281CB8,我们有理由相信这不是巧合,应该是对b.txt的dex做了修改。我们用十六进制编辑器修改偏移0x16D3A6位置修改为 0xD3,0x3D,然后拖进JEB查看。发现crypt函数内置的crypt_key变了,由原来的"kaokaonio"变成了"keepGoing",可见这是修改了资源ID。这下就清楚了,在encrypt_StepB(即crackjni)对ek处理,crypt函数使用后是"kaokaonio",而调用encrypt_StepB后,变为了"keepGoing",所以crypt再次变换使用了不同的rc_key。即正向变换应该为

结果如图,即flag{thisiskey!}为我们所求。
图片描述

题外,实际上在rc_key上走过的路并没那么顺畅就跳出坑了。一开始并没有反应过来两次使用的rc_key不一样,测试中都使用相同的rc_key=kaokaonio或keepGoing,结果自然失配。最后怀疑到crackjni使用的内置"kaokaonikaokaoni"会不会也修改成了其他值。但静态分析并没有发现由直接的修改,所以只能上测试机看下。实测中发现反调试还是如预料中那么”强大“。

六、上机
测试机是以前已经刷了官方开发版和unlock的红米,主要是对adb reboot命令和root权限无障碍。
图片描述
cmd命令行窗口1:

cmd命令行窗口2:

实际上我们目的只是想采集某个时态的内存情况,并不一定需要可以跑起来。
因为校验失败后,退出前有一定的停留,且这时候crackjni已经执行过,xtbl等都可能保留,这是我们捕捉的时机。
具体步骤如下:

图片描述
图片描述
图片描述
图片描述
如,可直接通过模块导出函数定位crackjni,也可以结合基址和偏移就定位到 ck="kaokaonikaokaoni"如图
Jump(0xCC4A7000+0xC2BE)
图片描述
图片描述
这里可以发现ck并没有改变(也可能改回去也不一定,只是假设)
图片描述
图片描述
图片描述
进一步跟进,通过prk和pck指针,我们可以得到 prk = crackjni(crypt(key="1234567890123456"))的运行结果
可以用于验证我们静态分析得到的正变换是否正确,如果逆向的正变换正确,则逆变换也正确;
题外:逆向的正逆变换本身可以自证,因为 anti_tranf(tranf(input))==input,正确性与正变换一致。
经过这个简单的拍照印证,可以确定下述正变换逻辑正确

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
import re
def decrypt_str(bs=''):
  cbs = re.findall('\\u00(..)',bs)
  for cb in cbs:
    bs = bs.replace('\\u00'+cb,chr(int(cb,0x10)))
  return ''.join([chr(ord(b)^0x10) for b in bs])
 
decrypt_str("q~tb\u007Fyt>s\u007F~du~d>`}>@qs{qwu@qbcub4@qs{qwu")
import re
def decrypt_str(bs=''):
  cbs = re.findall('\\u00(..)',bs)
  for cb in cbs:
    bs = bs.replace('\\u00'+cb,chr(int(cb,0x10)))
  return ''.join([chr(ord(b)^0x10) for b in bs])
 
decrypt_str("q~tb\u007Fyt>s\u007F~du~d>`}>@qs{qwu@qbcub4@qs{qwu")
 
 
 
 
 
 
 
 
 
 
 
s_ea = 0x1F004
e_ea = 0x1F2FB
cea = s_ea
ea_ss = {}
while cea <= e_ea:
  n = idc.Name(cea)
  if n:
    nea = cea
    bs = [idc.GetOriginalByte(cea)]
    cea+=1
    while idc.Name(cea)=='' and cea <= e_ea:
      bs.append(idc.GetOriginalByte(cea))
      cea+=1
    while len(bs)>0 and bs[-1]==0:
      bs.pop(-1)
    x = bs[-1]
    if nea in [0x1F0B8]:
      pass
    else:
      ea_ss[nea]= ''.join([chr(b^x) for b in bs])
      print("{:X}".format(nea),ea_ss[nea][:-1].__repr__())
      for i in range(len(ea_ss[nea])):
         idc.PatchByte(nea+i,ord(ea_ss[nea][i]))
      idc.MakeStr(nea,nea+len(ea_ss[nea]))
s_ea = 0x1F004
e_ea = 0x1F2FB
cea = s_ea
ea_ss = {}
while cea <= e_ea:
  n = idc.Name(cea)
  if n:
    nea = cea
    bs = [idc.GetOriginalByte(cea)]
    cea+=1
    while idc.Name(cea)=='' and cea <= e_ea:
      bs.append(idc.GetOriginalByte(cea))
      cea+=1
    while len(bs)>0 and bs[-1]==0:
      bs.pop(-1)
    x = bs[-1]
    if nea in [0x1F0B8]:
      pass
    else:
      ea_ss[nea]= ''.join([chr(b^x) for b in bs])
      print("{:X}".format(nea),ea_ss[nea][:-1].__repr__())
      for i in range(len(ea_ss[nea])):
         idc.PatchByte(nea+i,ord(ea_ss[nea][i]))
      idc.MakeStr(nea,nea+len(ea_ss[nea]))
结果如下
('1F004', "'/proc/self/task'")
('1F014', "'/proc/%d/task'")
('1F022', "'/proc/self/maps'")
('1F032', "'r'")
('1F034', "'r-xp'")
('1F039', "'%lx'")
('1F03D', "'/system/lib/'")
('1F04A', "'/odm/lib/'")
('1F054', "'/vendor/lib/'")
('1F061', "'openmemory'")
('1F06C', "'DexFile'")
('1F074', "'art'")
('1F078', "'OpenMemory'")
('1F083', "'OatDexFile'")
('1F090', "'LoadClassMembers'")
('1F0A1', "'ClassLinker'")
('1F0AD', "'LoadMethod'")
('1F0C0', "'ro.build.version.sdk'")
('1F0D5', "'\\x7fELF'")
('1F0E0', "'read /proc/self/maps'")
('1F0F5', "'/proc/self/maps'")
('1F105', "'frida'")
('1F10B', "'fdafd'")
('1F120', "'%x-%lx %4s %lx %*s %*s %s'")
('1F13A', "'.oat'")
('1F140', "'ro.product.cpu.abi'")
('1F160', "'ro.build.version.sdk'")
('1F175', "'libc.so'")
('1F17D', "'execve'")
('1F190', "'/system/lib/libart.so'")
('1F1A6', "'openmemory'")
('1F1C0', "'LoadClassMembers'")
('1F1E0', "'kaokaonikaokaoni'")
('1F200', "'com/kanxue/crackme/MyCrack'")
('1F21B', "'crypt'")
('1F230', "'Ljava/lang/String;'")
('1F250', "'l+x7fKd2FBaaEY4NV4309A==\\n'")
('1F270', "'ZmxhZ3RyeWFnYWluP30='")
('1F285', "'warn'")
('1F290', "'only support Android 7,Android 7.1,Android 8,Android 8.1,Android 9'")
('1F2D3', "'x86'")
('1F2E0', "'only support arm and arm64'")
结果如下
('1F004', "'/proc/self/task'")
('1F014', "'/proc/%d/task'")
('1F022', "'/proc/self/maps'")
('1F032', "'r'")
('1F034', "'r-xp'")
('1F039', "'%lx'")
('1F03D', "'/system/lib/'")
('1F04A', "'/odm/lib/'")
('1F054', "'/vendor/lib/'")
('1F061', "'openmemory'")
('1F06C', "'DexFile'")
('1F074', "'art'")
('1F078', "'OpenMemory'")
('1F083', "'OatDexFile'")
('1F090', "'LoadClassMembers'")
('1F0A1', "'ClassLinker'")
('1F0AD', "'LoadMethod'")
('1F0C0', "'ro.build.version.sdk'")
('1F0D5', "'\\x7fELF'")
('1F0E0', "'read /proc/self/maps'")
('1F0F5', "'/proc/self/maps'")
('1F105', "'frida'")
('1F10B', "'fdafd'")
('1F120', "'%x-%lx %4s %lx %*s %*s %s'")
('1F13A', "'.oat'")
('1F140', "'ro.product.cpu.abi'")
('1F160', "'ro.build.version.sdk'")
('1F175', "'libc.so'")
('1F17D', "'execve'")
('1F190', "'/system/lib/libart.so'")
('1F1A6', "'openmemory'")
('1F1C0', "'LoadClassMembers'")
('1F1E0', "'kaokaonikaokaoni'")
('1F200', "'com/kanxue/crackme/MyCrack'")
('1F21B', "'crypt'")
('1F230', "'Ljava/lang/String;'")
('1F250', "'l+x7fKd2FBaaEY4NV4309A==\\n'")
('1F270', "'ZmxhZ3RyeWFnYWluP30='")
('1F285', "'warn'")
('1F290', "'only support Android 7,Android 7.1,Android 8,Android 8.1,Android 9'")
('1F2D3', "'x86'")
('1F2E0', "'only support arm and arm64'")
 
 
 
 
 
from unicorn import *
from unicorn.arm_const import *
import sark
import idc
import struct
 
segs = list(sark.segments())
elf_base = segs[0].ea
elf_size = segs[-1].ea+segs[-1].size
elf_size = 0x1000*((elf_size+0x0FFF)/0x1000)
stack_size = 4*1024*1024
mem_size = 4*1024*1024
mem_ptr = elf_base + elf_size + stack_size
all_size = elf_size + stack_size + mem_size
stack_init = elf_base + elf_size + stack_size/2
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
mu.mem_map(elf_base, all_size)
print("Init Module: base:= {:06X} size:= {:04X}".format(elf_base,all_size))
for seg in segs:
  segdata = idc.get_bytes(seg.ea,seg.size)
  mu.mem_write(seg.ea, segdata)
  print("Init Seg: base:= {:06X} size:= {:04X}".format(seg.ea,seg.size))
 
ek_ptr = mem_ptr+0
ck_ptr = mem_ptr+0x100
rk_ptr = mem_ptr+0x200
mu.mem_write(ek_ptr,'T\xa7\xd0I;D\xaf\xe2d\xb2\x1b\x1cO%\x1d\x1e')#crypt('1234567890123456') kaokaonio
mu.mem_write(ck_ptr,"kaokaonikaokaoni")
mu.mem_write(rk_ptr,"\x00"*16)
SP=stack_init-0x448
mu.reg_write(UC_ARM_REG_SP,SP)
mu.mem_write(SP+0xBC,struct.pack("L",ek_ptr))
mu.mem_write(SP+0xB0,struct.pack("L",ck_ptr))
mu.mem_write(SP+0xAC,struct.pack("L",rk_ptr))
mu.emu_start(0xC2B8+1, 0x7F98) #实际由于StepB不对xtbl变换,可以模拟执行完整个正变换(0xC2B8+1, 0xC2C2)踩读取xtbl
xtbl_ea = 0x1F318
sbox_ea = 0x18F5B
xtbl = mu.mem_read(xtbl_ea,0x10*11)
sbox = mu.mem_read(sbox_ea,0x256)
from unicorn import *
from unicorn.arm_const import *
import sark
import idc
import struct
 
segs = list(sark.segments())
elf_base = segs[0].ea
elf_size = segs[-1].ea+segs[-1].size
elf_size = 0x1000*((elf_size+0x0FFF)/0x1000)
stack_size = 4*1024*1024
mem_size = 4*1024*1024
mem_ptr = elf_base + elf_size + stack_size
all_size = elf_size + stack_size + mem_size
stack_init = elf_base + elf_size + stack_size/2
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
mu.mem_map(elf_base, all_size)
print("Init Module: base:= {:06X} size:= {:04X}".format(elf_base,all_size))
for seg in segs:
  segdata = idc.get_bytes(seg.ea,seg.size)
  mu.mem_write(seg.ea, segdata)
  print("Init Seg: base:= {:06X} size:= {:04X}".format(seg.ea,seg.size))
 
ek_ptr = mem_ptr+0
ck_ptr = mem_ptr+0x100
rk_ptr = mem_ptr+0x200
mu.mem_write(ek_ptr,'T\xa7\xd0I;D\xaf\xe2d\xb2\x1b\x1cO%\x1d\x1e')#crypt('1234567890123456') kaokaonio
mu.mem_write(ck_ptr,"kaokaonikaokaoni")
mu.mem_write(rk_ptr,"\x00"*16)
SP=stack_init-0x448
mu.reg_write(UC_ARM_REG_SP,SP)
mu.mem_write(SP+0xBC,struct.pack("L",ek_ptr))
mu.mem_write(SP+0xB0,struct.pack("L",ck_ptr))
mu.mem_write(SP+0xAC,struct.pack("L",rk_ptr))
mu.emu_start(0xC2B8+1, 0x7F98) #实际由于StepB不对xtbl变换,可以模拟执行完整个正变换(0xC2B8+1, 0xC2C2)踩读取xtbl
xtbl_ea = 0x1F318
sbox_ea = 0x18F5B
xtbl = mu.mem_read(xtbl_ea,0x10*11)
sbox = mu.mem_read(sbox_ea,0x256)
def encrypt_StepB(ek):#Step正变换
  rk = ek
  if isinstance(ek,str):
    rk = [ord(c) for c in ek]
  rk = x16(rk,xtbl_xm(0))
  for i in range(1,10):
    rk = sbox_map(rk)
    rk = rxchg(rk)
    rk = cbx16(rk)
    rk = x16(rk,xtbl_xm(i))
  rk = sbox_map(rk)
  rk = rxchg(rk)
  rk = x16(rk,xtbl_xm(10))
  return ''.join([chr(v) for v in rk])
 
def decrypt_AntiStepB(rk):#Step逆变换
  rk = rk
  if isinstance(rk,str):
    rk = [ord(c) for c in rk]
  rk = x16(rk,xtbl_xm(10))
  rk = anti_rxchg(rk)
  rk = anti_sbox_map(rk)
  for i in range(9,0,-1):
    rk = x16(rk,xtbl_xm(i))
    rk = anti_cbx16(rk)
    rk = anti_rxchg(rk)
    rk = anti_sbox_map(rk)
  rk = x16(rk,xtbl_xm(0))
  return ''.join([chr(v) for v in rk])
 
def xtbl_xm(x):#选取xtbl第x行矩阵
  return xtbl[x*16:x*16+16]
 
def sbox_map(m):#sbox_map正变换
  r = [0]*len(m)
  for i,v in enumerate(m):
    r[i] = sbox[v]
  return r
 
def anti_sbox_map(m):#sbox_map逆变换
  r = [0]*len(m)
  for i,v in enumerate(m):
    r[i] = sbox.index(chr(v))
  return r
 
def x16(a,b):#行矩阵异或
  c = [0]*16
  for i in range(16):
    c[i]=a[i]^b[i]
  return c
 
def rxchg(r):#行元素位置正交换
  v = r[1]
  r[1]=r[5]
  r[5]=r[9]
  r[9]=r[13]
  r[13]=v
  #
  v=r[2]
  r[2]=r[10]
  r[10]=v
  #
  v=r[6]
  r[6]=r[14]
  r[14]=v
  #
  v=r[3]
  r[3]=r[15]
  r[15]=r[11]
  r[11]=r[7]
  r[7]=v
  return r
 
def anti_rxchg(r):#行元素位置逆交换
  v=r[7]
  r[7]=r[11]
  r[11]=r[15]
  r[15]=r[3]
  r[3]=v
  #
  v=r[14]
  r[14]=r[6]
  r[6]=v
  #
  v = r[10]
  r[10]=r[2]
  r[2]=v
  #
  v=r[13]
  r[13]=r[9]
  r[9]=r[5]
  r[5]=r[1]
  r[1]=v
  return r
 
def bxchg(b):#字节Noekeon正变换,姑且起名Noekeon
  b = c_ubyte(b)
  bm = b.value&0x80
  b.value = b.value << 1
  if bm:
    b.value ^= 0b00011011
  else:
    b.value ^= 0b00000000
  return b.value
 
def anti_bxchg(b):#字节Noekeon负变换
  b = c_ubyte(b)
  bm = b.value&1
  if bm:
    b.value ^= 0b00011011
  else:
    b.value ^= 0b00000000
  b.value = b.value >> 1
  b.value = b.value|0x80 if bm else b.value
  return b.value
 
def cbx4(m):#4字节Noekeon正变换
  c0,c1,c2,c3=m
  cx = c0
  cy = c0^c1^c2^c3
  t0 = c0 ^ cy ^ bxchg(c0^c1)
  t1 = c1 ^ cy ^ bxchg(c2^c1)
  t2 = c2 ^ cy ^ bxchg(c3^c2)
  t3 = c3 ^ cy ^ bxchg(c3^c0)
  bm = [t0,t1,t2,t3]
  return bm
 
def cbx16(m):#16字节Noekeon正变换
  bm = []
  for i in range(0,16,4):
    bm+=cbx4(m[i:i+4])
  return bm
 
def anti_cbx4(m):#4字节Noekeon负变换
  t0,t1,t2,t3 = m
  cy = t0^t1^t2^t3
  for rx in range(0,0x100):
    r0 = rx
    r1 = anti_bxchg(t0^cy^r0)^r0
    r2 = anti_bxchg(t1^cy^r1)^r1
    r3 = anti_bxchg(t2^cy^r2)^r2
    br0 = anti_bxchg(t3^cy^r3)^r3
    if r0==br0:
      return [r0,r1,r2,r3]
      #print(r0,r1,r2,r3)
 
def anti_cbx16(m):#16字节Noekeon负变换
  bm = []
  for i in range(0,16,4):
    bm+=anti_cbx4(m[i:i+4])
  return bm
 
from Crypto.Cipher import ARC4
def myRC4(data,key='kaokaonio'):
    rc41 = ARC4.new(key)
    encrypted = rc41.encrypt(data)
 
def crypt(p,key='keepGoing'):#crypt,实际就是RC41,可用 myRC4替换
  pm = p
  if isinstance(p,str):
    pm = [ord(c) for c in p]
  #bk = [ord(c) for c in 'kaokaonio']
  bk = [ord(c) for c in key]
  bk_len = len(bk)
  bm = [i for i in range(0x100)]
  k = 0
  m = 0
  for i in range(0x100):
    m = (m + bk[k] + bm[i])&0xFF
    t = bm[i]
    bm[i] = bm[m]
    bm[m] = t
    k = (k+1)%bk_len
  #
  pm_len = len(pm)
  rm = [0]*pm_len
  x = 0
  y = 0
  for i in range(pm_len):
    x = (x+1)&0xFF
    y = (y+bm[x])&0xFF
    t = bm[x]
    bm[x]=bm[y]
    bm[y]=t
    n = (bm[x]+bm[y])&0xFF
    rm[i]=pm[i]^bm[n]
  return rm
 
def ts(m):#矩阵到字符串
  return ''.join([chr(c_ubyte(i).value) for i in m])
 
def tm(s):#字符串到矩阵
  return [ord(i) for i in s]
 
def prk(m):#辅助打印矩阵或字符串
  if isinstance(m,str):
    print(' '.join(["{:02X}".format(ord(c)) for c in m]))
  else:
    print(' '.join(["{:02X}".format(c) for c in m]))
def encrypt_StepB(ek):#Step正变换
  rk = ek
  if isinstance(ek,str):
    rk = [ord(c) for c in ek]
  rk = x16(rk,xtbl_xm(0))
  for i in range(1,10):
    rk = sbox_map(rk)
    rk = rxchg(rk)
    rk = cbx16(rk)
    rk = x16(rk,xtbl_xm(i))
  rk = sbox_map(rk)
  rk = rxchg(rk)
  rk = x16(rk,xtbl_xm(10))
  return ''.join([chr(v) for v in rk])
 
def decrypt_AntiStepB(rk):#Step逆变换
  rk = rk
  if isinstance(rk,str):
    rk = [ord(c) for c in rk]
  rk = x16(rk,xtbl_xm(10))
  rk = anti_rxchg(rk)
  rk = anti_sbox_map(rk)
  for i in range(9,0,-1):
    rk = x16(rk,xtbl_xm(i))
    rk = anti_cbx16(rk)
    rk = anti_rxchg(rk)
    rk = anti_sbox_map(rk)
  rk = x16(rk,xtbl_xm(0))
  return ''.join([chr(v) for v in rk])
 
def xtbl_xm(x):#选取xtbl第x行矩阵
  return xtbl[x*16:x*16+16]
 
def sbox_map(m):#sbox_map正变换
  r = [0]*len(m)
  for i,v in enumerate(m):
    r[i] = sbox[v]
  return r
 
def anti_sbox_map(m):#sbox_map逆变换
  r = [0]*len(m)
  for i,v in enumerate(m):
    r[i] = sbox.index(chr(v))
  return r
 
def x16(a,b):#行矩阵异或
  c = [0]*16

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-11-24 12:47 被HHHso编辑 ,原因:
上传的附件:
收藏
免费 4
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//