其他
一种还原白盒AES秘钥的方法
本文为看雪论坛优秀文章
看雪论坛作者ID:lfyyy
在日常逆向分析工作有遇到过一个白盒AES算法,在网上找到这样一篇还原该白盒算法秘钥的文章:
DFA分析白盒AES算法 ,通过学习该文章,总结了一些心得,在这里分享下。
详细的理论可以看上面那篇blog,我这里只挑一些重点来说明下。
>>>> AES算法
AES算法
AES算是我们日常开发中最常用一种对称加密算法了,加密过程如下:
>>>> 白盒AES算法
白盒AES算法
>>>> DFA分析AES-128加密
DFA分析AES-128加密
MixColumns
AddRoundKey K9
SubBytes
ShiftRows
AddRoundKey K10
详细推导过程可以参照原文blog。
>>>> DFA算法实现
DFA算法实现
算法输入
算法输出
算法关键点说明
# AES decryption
[[True, False, False, False, False, True, False, False, False, False, True, False, False, False, False, True],
[False, True, False, False, False, False, True, False, False, False, False, True, True, False, False, False],
[False, False, True, False, False, False, False, True, True, False, False, False, False, True, False, False],
[False, False, False, True, True, False, False, False, False, True, False, False, False, False, True, False]],
# AES encryption
[[True, False, False, False, False, False, False, True, False, False, True, False, False, True, False, False],
[False, True, False, False, True, False, False, False, False, False, False, True, False, False, True, False],
[False, False, True, False, False, True, False, False, True, False, False, False, False, False, False, True],
[False, False, False, True, False, False, True, False, False, True, False, False, True, False, False, False]]
]
状态矩阵乘法
核心算法
print ("_get_compat","diff:%x" % diff, "tmult:%x" %tmult)
ibox = [_AesSBox, _AesInvSBox][encrypt]
itab = [0]*256
for i,mi in enumerate(_AesMult[tmult]):
itab[mi] = i
candi = [itab[ibox[j ^ diff] ^ ibox_j] for j, ibox_j in enumerate(ibox)]
return candi
invSBox(diff + S(Y0)) = Y0 + 2z
invSBox(diff + S(Y0)) + Y0 = 2z
candi = [itab[ibox[j ^ diff] ^ ibox_j] for j, ibox_j in enumerate(ibox)]
>>>> java层分析
java层分析
>>>> native层分析
native层分析
jsCode = """
function hookOAES() {
var fnPtr = Module.findExportByName("libnative-lib.so", "_Z48TfcqPqf1lNhu0DC2qGsAAeML0SEmOBYX4jpYUnyT8qYWIlEqPhS_");
var oldfnPtr = new NativeFunction(fnPtr, 'int', ['pointer', 'pointer']);
Interceptor.replace(fnPtr, new NativeCallback(function (input, output) {
send("***********OAES***********")
var arg0 = Memory.readByteArray(input,16);
console.log("a0:" + hexdump(arg0));
var arg1 = Memory.readByteArray(output,16);
console.log("a1 before:" + hexdump(arg1));
var ret = oldfnPtr(input,output);
var arg2 = Memory.readByteArray(output,16);
console.log("a1 after:" + hexdump(arg2));
return ret;
}, 'int', ['pointer', 'pointer']));
}
Java.perform(function(){
send("***************Start hook***************");
var Main = Java.use("kr.repo.h2spice.crypto500.MainActivity");
Main.a.overload("java.lang.String").implementation = function (input) {
input = "Gew1cqzKp5K8sejh3FlTZlS/CISCpO81WmZ/oU4SJOk=";
console.log("native-input:" + input);
var ret = this.a(input);
console.log("native-output:" + ret);
return ret;
}
Main.onCreate.overload("android.os.Bundle").implementation= function (bundle) {
console.log("MainActivity onCreate!!!");
return this.onCreate(bundle);
}
hookOAES();
});
"""
return jsCode
>>>> 秘钥还原
秘钥还原
import idc
import idaapi
import breakFunctions
import time
import linecache
import dumpmemory
import random
soName = 'libnative-lib.so'
module_base = breakFunctions.findModleBaseByName(soName)
gloden_ref = "868FC14BCCC36E3C657B73271A32DCD7"
# AESEnc
sub_4250 = module_base + 0x4250
sub_59A6 = module_base + 0x59A6
sub_46A4 = module_base + 0x46A4
sub_4DBC = module_base + 0x4DBC
def main():
idc.AddBpt(sub_4250)
idc.MakeComm(sub_4250, "### WBoxAES START###")
print "[+]set breakpoint addr=>0x%X %s" % (sub_4250, "sub_4250")
idc.AddBpt(sub_59A6)
idc.MakeComm(sub_59A6, "### WBoxAES END###")
print "[+]set breakpoint addr=>0x%X %s" % (sub_59A6, "sub_59A6")
idc.AddBpt(sub_4DBC)
idc.MakeComm(sub_4DBC, "### BL Z48lrsFdMdlAT0vSMVedxmqOkCBF7sCTbhCjYEp1rLP8vatWEGDPh###")
print "[+]set breakpoint addr=>0x%X %s" % (sub_4DBC, "sub_4DBC")
idc.AddBpt(sub_46A4)
idc.MakeComm(sub_46A4, "### sub_46A4 ###")
print "[+]set breakpoint addr=>0x%X %s" % (sub_46A4, "sub_46A4")
auto_run_test()
def auto_run_test():
logpath = "C:\\Users\\felix.li\\Desktop\\Crypto500_WAESCrack1.txt"
f = open(logpath, "a")
f.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) + "*****START******\n")
for i in range(16):
runTo(sub_4250)
count = 0
is_this_round = True
while True:
addr = idc.GetEventEa()
if addr == sub_4250:
f.write("OAES START\n")
print ("OAES START\n")
R0 = idc.GetRegValue("R0")
R1 = idc.GetRegValue("R1")
srcR0 = toHexString(getMemory(R0, 16))
print srcR0
if srcR0.lower() != "19ec3572accaa792bcb1e8e1dc595366":
print "not this round"
f.write("not this round\n")
is_this_round = False
break
f.write("srcHexstr:" + srcR0 + "\n")
ret_address = R1
print hex(ret_address)
if addr == sub_59A6:
f.write("OAES END\n")
print ("OAES END")
print hex(ret_address)
desret = toHexString(getMemory(ret_address, 16))
print "resHexstr:" + desret
f.write("resHexstr:" + desret + "\n")
break
if addr == sub_4DBC:
# f.write("BL lrsFdMdlAT0vSMVedxmqOkCBF7sCTbhCjYEp1rLP8vatWEGD\n")
print ("BL lrsFdMdlAT0vSMVedxmqOkCBF7sCTbhCjYEp1rLP8vatWEGD")
if addr == sub_46A4:
# f.write("sub_46A4\n")
print ("sub_46A4")
count = count + 1
if count == 33:
print hex(ret_address)
desret = toHexString(getMemory(ret_address, 16))
print "patch current state:" + desret
idc.PatchByte(ret_address + random.randint(0,15), random.randint(0,255))
idaapi.continue_process()
idaapi.wait_for_next_event(idc.WFNE_ANY, -1)
event = idc.GetDebuggerEvent(idc.WFNE_ANY, -1)
if (event <= 1):
break
if not is_this_round:
idaapi.continue_process()
idaapi.wait_for_next_event(idc.WFNE_ANY, -1)
def runTo(ea):
addr = idc.GetEventEa()
while addr != ea:
idaapi.continue_process()
idaapi.wait_for_next_event(idc.WFNE_ANY, -1)
addr = idc.GetEventEa()
with open('tracefile', 'wb') as t:
t.write("""
868FC14BCCC36E3C657B73271A32DCD7
998FC14BCCC36E7F657B61271AC0DCD7
86C5C14B32C36E3C657B73911A32E8D7
868FAF4BCC6D6E3C267B73271A32DC1B
8630C14B4BC36E3C657B73A41A32B7D7
868FE74BCC096E3C957B73271A32DC9E
86ADC14B7DC36E3C657B73881A32A4D7
868FC1FFCCC3A13C653E7327A032DCD7
9B8FC14BCCC36E3F657B0A271A87DCD7
BC8FC14BCCC36E09657BF3271AAEDCD7
8622C14B62C36E3C657B73E71A3224D7
868FA34BCC8B6E3C1B7B73271A32DC4C
868FC1CACCC3D73C654473270032DCD7
658FC14BCCC36E52657B79271AE4DCD7
867EC14B23C36E3C657B73A91A328AD7
258FC14BCCC36E83657B55271A26DCD7
E78FC14BCCC36EE1657B44271AA7DCD7
""".encode('utf8'))
phoenixAES.crack_file('tracefile',[],True,False,3)
K00: 6C2893F21B6185E8567238CB78184945
K01: C013FD4EDB7278A68D00406DF5180928
K02: 6F12C9A8B460B10E3960F163CC78F84B
K03: D7537AE36333CBED5A533A8E962BC2C5
K04: 2E76DC734D45179E17162D10813DEFD5
K05: 19A9DF7F54ECC8E143FAE5F1C2C70A24
K06: FFCEE95AAB2221BBE8D8C44A2A1FCE6E
K07: 7F4576BFD46757043CBF934E16A05D20
K08: 1F09C1F8CB6E96FCF7D105B2E1715892
K09: A7638E006C0D18FC9BDC1D4E7AAD45DC
K10: 040D08DA68001026F3DC0D68897148B4
* IDA 动态Patch的方式,这种需要分析代码,找准patch的时机。
看雪ID:lfyyy
https://bbs.pediy.com/user-608531.htm
推荐文章++++
* 拨云见日:安卓APP脱壳的本质以及如何快速发现ART下的脱壳点
* Metasploit BlueKeep漏洞利用模块简要分析