样本为某app里面的libmsaoaidsec.so的init_proc方法,没有原因,就是顺手就撸了,刚好看反调试看到这个东西就尝试了一下以前的一个设想
目前对于控制流平坦化比较常规的一种处理方式是对代码分块后,然后根据虚假块的特征删除后虚假块,然后通过动态或静态unicorn跑出流程,再把真实块之间的关系进行关联之后PatchCode,这种方式处理起来比较简单,但是容易导致流程出错,特别是碰到那种无法确定结果的分支时容易出错。对于虚假块与真实块的区分,除了特征识别外,据我观察,这种控制流平坦化从逻辑上来说其实跟二叉树查找差不多(那种特复杂的另算),每个真实块基本都在树的枝头上,ret块直接反回,其它块填充新的key值进行下一个流程块的转移,基本上终点回到分发器的都是真实块。还有一种比较高端的貌似是使用中间指令进行转换之后再通过编译原理的各种操作进行优化后进行重组,这种只是听说过没见过具体实现,只能说非常之高大上,只能膜拜。
平常使用的也是前一种方法,看个大概,然后动态调,后来有想过搞一套全自动的,结果搞了一半电脑坏了,然后弄了一半的代码被我给一不小心咔嚓掉了也就到了现在。
现在这套代码也是在被咔嚓的代码的基本思路上重新进行的开发,整个思路其实很简单,代理掉寄存器的读和写操作,代理掉内存的读和写操作,直接从头跑到尾,跑出所有分支,之后再处理。整体而言没有太过于注重“分发器、虚假块、真实块”这类概念。以这种方式处理,那么有些问题就必需解决
先上效果,流程属于那种简单的那种,所以没什么特别的东西 在处理前的cfg视图 idaF5的效果
代码分块需要注意的主要问题有: 1.碰到跳转就分块,跳转的目标也是一个块的分界点 2.csel指令下面也需要分块,这个指令比较特殊,必需放在块的未尾,这样便于处理分流问题 3.每一个块都需要能够直接通过块信息查询到他可能的跳转信息 比如:
以Object来保存寄存器状态,只处理常量,例部分接口:
所有对寄存器的操作全部走这些接口,便于管理,其中部分寄存器需要特殊处理,在碰到bl指令时清空x0-x7等都需要特殊对待,如果有用到X30等也得处理
内存的操作与寄存器操作类似,不过内存的问题在地地址交叉问题,这里我使用的是设置一个map,以地址作为key,每个key只与一个byte对应,然后读写操作针对这个map去进行读写,这样可以确保某些情况下局部变量被用作常量缓存的问题,例如下面这种情况的准确处理
例如部分内存操作的代码:
像寄存器和内存的代理处理后基本上已经可以处理大部分的情况了
对于路径问题我这里采用的是递归,每一个代码块都有属于它自己的寄存器环境、内存环境等,对于大部分赋值指令进行手动模拟,对于cmp、tst、b.XX、csel等这类指令则在参数均为常量时进行unicorn模拟执行单条指令,因为这样代码简单且准确度更高
避免死循环,主要就是针块的下一个跳转存在多解的情况进行处理,比如,对csel的特殊处理如下,其它的多解类似,上面的代码中有包含:
最终的效果就如下面的这样
总共跑出8条分支,List中的顺序即为块的顺序,存在分歧的地方即为多解的块,在这里都是csel,这里有个小技巧,就是csel的条件满足时走的分支会在前面,这是由代码特性决定的。 比如
假设这个结果不唯一,那么,在走到这里时会返回两个分支[x8, x9],之后在递归时,会先走x8分支再走x9分支,所以出结果必然是x8在前x9在后
最后上一下最终的效果吧: 处理后idaF5的效果(ida的CFG视图就不上了,CFG会保留那些无法到达的块,看起来还是挺恶心)
sub_8c38大一些,cfg 处理后的效果:
这种方式处理的优点个人感觉就是流程准确度更高,缺点就是每碰到一个新的指令就需要增加对新指令的处理代码,如果指令处理出错也会出现问题,属于有点体力活的感觉,再则,当流程跑出来后如果有兴趣可以增加更加智能化的处理,比如自动识别虚假块,自动Patch等
因为每一个块执行时当时的寄存器环境等都有缓存,所以,对于跑出的每一个分支其实都是可以进行常量扫描的,可以做的事情很多,比如如果有编译原理的知识,可以对那些赋值却没有用的语句进行nop处理,或只是把可以优化的指令行标记出来,为后续patch增加修复空间等,这东西patch起来需要考虑很多问题,所以这里我选择的是手动patch,看似路径很多,其实都多都是重叠的,如果想进一步缩小手动处理的范围,还可以针对明确的地址进行优先patch,然后把有不确定性的打印出来手动处理,那样的话手动处理的代码就会很少很少,基本就是那些csel之类的指令了
完整的脚本代码附件,太长了。。。:
脚本使用方式很简单(需要安装对应的库):shift+f2调出脚本界面 --> 鼠标焦点放在要扫描的函数体内任意地方 --> 点击脚本界面的“run” --> 根据结果修改virtualBlock表,如有不识别的指令就修改脚本增中处理 --> 最终结果直接Patch即可
脚本有很多问题,对很多指令都没有处理,需要在实际过程中去碰到时进行增加,再则是对影响nzcv寄存器有影响的指令,对sp有回写操作的指令等,这个可以根据Capstone解析出的那个update_flags和writeback是否为True来识别,一般来说这类指令在判定为常量时可以直接放unicorn进行跑一下,这样可以省去很多过程且准确度更高
还有一种是直接通过unicorn直接跑整个代码,然后在碰到csel指令时对分支进行控制,不过unicorn跑的时候所有寄存器都有一个默认值,再则不一定所有不确定分支都是在csel这个指令下进行的分流,虽说这条指令本身就是为这个优化做的,内存访问也需要特殊处理,这些都是需要注意的地方,如果有兴趣可以自行研究
1.
代码分块,怎么分块很重要,后续的所有操作都是以代码分的块为单位处理的
2.
寄存器读写代理,寄存器常量与非常量的表示,包括有效位数,比如w0与x0等
3.
内存访问与写入代理,内存数据的表示形式,比如往A地址写入
long
常量,
+
4
的位置读取
int
也应判定为常量的问题
4.
如何跑出所有路径的问题,比如某些函数返回后,在之后的流程会根据这个结果走不同的流程等,而且不止一个地方
5.
如何避免死循环,性于跑出所有路径问题的延伸,如果不进行处理可能会进入类似于∞的死循环中
1.
代码分块,怎么分块很重要,后续的所有操作都是以代码分的块为单位处理的
2.
寄存器读写代理,寄存器常量与非常量的表示,包括有效位数,比如w0与x0等
3.
内存访问与写入代理,内存数据的表示形式,比如往A地址写入
long
常量,
+
4
的位置读取
int
也应判定为常量的问题
4.
如何跑出所有路径的问题,比如某些函数返回后,在之后的流程会根据这个结果走不同的流程等,而且不止一个地方
5.
如何避免死循环,性于跑出所有路径问题的延伸,如果不进行处理可能会进入类似于∞的死循环中
block addr:
0x13894
0x13894
: movz w9,
0x13898
: movk w9,
0x1389c
:
cmp
w8, w9
0x138a0
: b.ne
jmpto
-
> [
'0x136e8'
,
'0x138a4'
]
block addr:
0x138a4
0x138a4
: ldr w8, [sp,
0x138a8
: movz w9,
0x138ac
: movk w9,
0x138b0
:
cmp
w8,
0x138b4
: movz w8,
0x138b8
: movk w8,
0x138bc
: csel w8, w9, w8, eq
jmpto
-
> [
'0x138c0'
]
block addr:
0x138c0
0x138c0
: b
jmpto
-
> [
'0x136e8'
]
block addr:
0x13894
0x13894
: movz w9,
0x13898
: movk w9,
0x1389c
:
cmp
w8, w9
0x138a0
: b.ne
jmpto
-
> [
'0x136e8'
,
'0x138a4'
]
block addr:
0x138a4
0x138a4
: ldr w8, [sp,
0x138a8
: movz w9,
0x138ac
: movk w9,
0x138b0
:
cmp
w8,
0x138b4
: movz w8,
0x138b8
: movk w8,
0x138bc
: csel w8, w9, w8, eq
jmpto
-
> [
'0x138c0'
]
block addr:
0x138c0
0x138c0
: b
jmpto
-
> [
'0x136e8'
]
def
initRegObj():
regObj
=
{}
regObj[
"isConst"
]
=
False
regObj[
"val"
]
=
-
1
regObj[
"validBit"
]
=
0
return
regObj
def
readReg(constRegs, regId):
regIdTmp
=
getXRegId(regId)
if
regIdTmp
=
=
ARM64_REG_XZR:
return
initRegObjImm(
True
,
0
, getRegValidByte(regId))
if
regIdTmp
in
constRegs:
return
constRegs[regIdTmp]
return
initRegObj()
def
writeReg(constRegs, regId, regObj):
regIdTmp
=
getXRegId(regId)
if
regIdTmp
=
=
ARM64_REG_XZR:
return
;
constRegs[regIdTmp]
=
regObj
if
isRegConst(regObj) !
=
True
:
del
constRegs[regIdTmp]
else
:
regObj[
"validBit"
]
=
regObj[
"validBit"
] | getRegValidByte(regId)
def
getRegValidByte(regId):
if
ARM64_REG_X0 <
=
regId
and
regId <
=
ARM64_REG_X28:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_X29
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_X30
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_XZR
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_SP
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_NZCV
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_W0 <
=
regId
and
regId <
=
ARM64_REG_W30:
return
0xFFFFFFFF
if
ARM64_REG_WZR
=
=
regId:
return
0xFFFFFFFF
return
0
def
initRegObj():
regObj
=
{}
regObj[
"isConst"
]
=
False
regObj[
"val"
]
=
-
1
regObj[
"validBit"
]
=
0
return
regObj
def
readReg(constRegs, regId):
regIdTmp
=
getXRegId(regId)
if
regIdTmp
=
=
ARM64_REG_XZR:
return
initRegObjImm(
True
,
0
, getRegValidByte(regId))
if
regIdTmp
in
constRegs:
return
constRegs[regIdTmp]
return
initRegObj()
def
writeReg(constRegs, regId, regObj):
regIdTmp
=
getXRegId(regId)
if
regIdTmp
=
=
ARM64_REG_XZR:
return
;
constRegs[regIdTmp]
=
regObj
if
isRegConst(regObj) !
=
True
:
del
constRegs[regIdTmp]
else
:
regObj[
"validBit"
]
=
regObj[
"validBit"
] | getRegValidByte(regId)
def
getRegValidByte(regId):
if
ARM64_REG_X0 <
=
regId
and
regId <
=
ARM64_REG_X28:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_X29
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_X30
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_XZR
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_SP
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_NZCV
=
=
regId:
return
0xFFFFFFFFFFFFFFFF
if
ARM64_REG_W0 <
=
regId
and
regId <
=
ARM64_REG_W30:
return
0xFFFFFFFF
if
ARM64_REG_WZR
=
=
regId:
return
0xFFFFFFFF
return
0
str
x8, [sp,
sub sp, sp,
...
add x8, sp,
ldr x8, [x8]
str
x8, [sp,
sub sp, sp,
...
add x8, sp,
ldr x8, [x8]
def
initMemObj(isConst, val, validBit):
memObj
=
{}
memObj[
"isConst"
]
=
isConst
memObj[
"val"
]
=
val
memObj[
"validBit"
]
=
validBit
return
memObj
def
isMemObjConst(memObj):
return
memObj[
"isConst"
]
def
getMemObjVal(memObj):
if
memObj[
"isConst"
]:
return
memObj[
"val"
] & memObj[
"validBit"
]
return
-
1
def
readByte(constMems, addr):
ret
=
readMem(constMems, addr,
1
)
if
ret !
=
None
and
(
len
(ret)
=
=
1
):
return
initMemObj(
True
,
int
.from_bytes(ret,
"big"
),
0xFF
)
return
initMemObj(
False
,
0
,
0
)
def
readInt4(constMems, addr, s):
ret
=
readMem(constMems, addr,
4
)
if
ret !
=
None
and
(
len
(ret)
=
=
4
):
return
initMemObj(
True
,
int
.from_bytes(ret,
"big"
),
0xFFFFFFFF
)
return
initMemObj(
False
,
0
,
0
)
def
readMem(constMems, addr, sz):
if
sz <
=
0
:
return
None
;
ret
=
[
0
]
*
sz
for
i
in
range
(
0
, sz):
if
(addr
+
i)
in
constMems:
ret[i]
=
constMems[addr
+
i] &
0xff
else
:
ret
=
None
break
if
ret !
=
None
:
return
bytes(ret)
return
None
def
writeMem(constMems, addr, sz, data):
minLen
=
sz
if
len
(data) < sz:
minLen
=
sz
for
i
in
range
(
0
, minLen):
constMems[addr
+
i]
=
data[i] &
0xff
def
writeInvalidMem(constMems, addr, sz):
for
i
in
range
(
0
, sz):
if
(addr
+
i)
in
constMems:
del
constMems[addr
+
i]
def
initMemObj(isConst, val, validBit):
memObj
=
{}
memObj[
"isConst"
]
=
isConst
memObj[
"val"
]
=
val
memObj[
"validBit"
]
=
validBit
return
memObj
def
isMemObjConst(memObj):
return
memObj[
"isConst"
]
def
getMemObjVal(memObj):
if
memObj[
"isConst"
]:
return
memObj[
"val"
] & memObj[
"validBit"
]
return
-
1
def
readByte(constMems, addr):
ret
=
readMem(constMems, addr,
1
)
if
ret !
=
None
and
(
len
(ret)
=
=
1
):
return
initMemObj(
True
,
int
.from_bytes(ret,
"big"
),
0xFF
)
return
initMemObj(
False
,
0
,
0
)
def
readInt4(constMems, addr, s):
ret
=
readMem(constMems, addr,
4
)
if
ret !
=
None
and
(
len
(ret)
=
=
4
):
return
initMemObj(
True
,
int
.from_bytes(ret,
"big"
),
0xFFFFFFFF
)
return
initMemObj(
False
,
0
,
0
)
def
readMem(constMems, addr, sz):
if
sz <
=
0
:
return
None
;
ret
=
[
0
]
*
sz
for
i
in
range
(
0
, sz):
if
(addr
+
i)
in
constMems:
ret[i]
=
constMems[addr
+
i] &
0xff
else
:
ret
=
None
break
if
ret !
=
None
:
return
bytes(ret)
return
None
def
writeMem(constMems, addr, sz, data):
minLen
=
sz
if
len
(data) < sz:
minLen
=
sz
for
i
in
range
(
0
, minLen):
constMems[addr
+
i]
=
data[i] &
0xff
def
writeInvalidMem(constMems, addr, sz):
for
i
in
range
(
0
, sz):
if
(addr
+
i)
in
constMems:
del
constMems[addr
+
i]
def
getBlockNextAddr(curBlock):
if
"jmpto"
in
curBlock:
return
curBlock[
"jmpto"
]
return
None
runOnceBlock
=
{}
def
runFuzz(constRegs, constMems, curBlock):
ret
=
[]
if
curBlock[
"startAddr"
]
in
runOnceBlock:
if
runOnceBlock[curBlock[
"startAddr"
]]
=
=
True
:
print
(
"run once block, return."
)
return
None
try
:
for
codeitem
in
curBlock[
"codes"
]:
if
testAsm(constRegs, constMems, codeitem)
=
=
False
:
regsRead
=
codeitem[
"regsRead"
]
regsWrite
=
codeitem[
"regsWrite"
]
operands
=
codeitem[
"operands"
]
if
ARM64_INS_CMP
=
=
codeitem[
"id"
]:
asmUniCmp(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
], codeitem[
"opTypes"
],
codeitem[
"operands"
])
elif
ARM64_INS_TST
=
=
codeitem[
"id"
]:
asmUniTst(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
], codeitem[
"opTypes"
],
codeitem[
"operands"
])
elif
ARM64_INS_B
=
=
codeitem[
"id"
]:
bret
=
asmUniB(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
], codeitem[
"opTypes"
],
codeitem[
"operands"
], codeitem[
"cc"
])
if
bret !
=
None
:
print
([
hex
(x)
for
x
in
bret])
if
len
(bret) >
1
:
runOnceBlock[curBlock[
"startAddr"
]]
=
True
env
=
{}
env[
"regs"
]
=
constRegs
env[
"mems"
]
=
constMems
env[
"nextAddr"
]
=
bret
ret.append(env)
return
ret
elif
ARM64_INS_CSEL
=
=
codeitem[
"id"
]:
dstRegId, srcRegIdList
=
asmUniCsel(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
],
codeitem[
"opTypes"
], codeitem[
"operands"
])
if
len
(srcRegIdList) >
1
:
for
regId
in
srcRegIdList:
srcRegId
=
regId
cpyConstRegs
=
copy.deepcopy(constRegs)
writeReg(cpyConstRegs, dstRegId, readReg(cpyConstRegs, srcRegId))
env
=
{}
env[
"regs"
]
=
cpyConstRegs
env[
"mems"
]
=
constMems
env[
"nextAddr"
]
=
[
int
(codeitem[
"addr"
],
16
)
+
4
]
ret.append(env)
runOnceBlock[curBlock[
"startAddr"
]]
=
True
return
ret
else
:
print
(
"------------ only one result. -----------"
)
elif
ARM64_INS_RET
=
=
codeitem[
"id"
]:
return
None
else
:
print
(
"unknow ins."
)
if
getBlockNextAddr(curBlock)
=
=
None
:
print
(
"curBlock has not next block."
)
return
None
env
=
{}
env[
"regs"
]
=
constRegs
env[
"mems"
]
=
constMems
env[
"nextAddr"
]
=
getBlockNextAddr(curBlock)
ret.append(env)
return
ret
except
Exception as e:
print
(
repr
(e))
print
(traceback.format_exc())
return
None
virtualBlock
=
[
0x136e8
,
0x13774
,
0x1377c
,
0x13784
,
0x13794
,
0x137a4
,
0x136f0
,
0x136f8
,
0x137c4
,
0x138c4
,
0x138d4
,
0x13858
,
0x137cc
,
0x137d4
,
0x13884
,
0x13894
,
0x13810
,
0x13818
,
0x13820
,
0x13830
,
0x13854
,
0x138f8
,
0x13908
,
0x13960
,
0x138c0
,
0x13868
,
0x13870
,
0x13880
,
0x13700
,
0x13708
,
0x13a44
,
0x13718
,
0x13770
,
0x137e4
]
def
removeVirtualBlock(callStack):
for
item
in
range
(
len
(callStack)
-
1
,
-
1
,
-
1
):
for
addr
in
virtualBlock:
if
callStack[item]
=
=
addr:
del
callStack[item]
break
return
callStack
def
getBlockFeature(codeblock, blockAddr):
feature
=
""
if
blockAddr
in
codeblock:
curBlock
=
codeblock[blockAddr]
for
codeitem
in
curBlock[
"codes"
]:
feature
=
feature
+
codeitem[
"mnemonic"
]
+
codeitem[
"opTypes"
]
return
feature
def
testFuzzBlock(constRegs, constMems, codeblock, curBlock, callStack):
curConstRegs
=
copy.deepcopy(constRegs)
curConstMems
=
copy.deepcopy(constMems)
callStack.append(curBlock[
"startAddr"
])
endEnv
=
runFuzz(curConstRegs, curConstMems, curBlock)
if
endEnv
=
=
None
:
callStack
=
removeVirtualBlock(callStack)
print
([
hex
(x)
for
x
in
callStack])
return
else
:
for
env
in
endEnv:
subRegs
=
env[
"regs"
]
subMems
=
env[
"mems"
]
nextAddrList
=
env[
"nextAddr"
]
if
nextAddrList !
=
None
:
for
nextBlockAddr
in
nextAddrList:
nextBlock
=
codeblock[nextBlockAddr]
curCallStack
=
copy.deepcopy(callStack)
testFuzzBlock(subRegs, subMems, codeblock, nextBlock, curCallStack)
writeReg(constRegs, ARM64_REG_SP, initRegObjImm(
True
,
0x10000
, getRegValidByte(ARM64_REG_SP)))
def
getBlockNextAddr(curBlock):
if
"jmpto"
in
curBlock:
return
curBlock[
"jmpto"
]
return
None
runOnceBlock
=
{}
def
runFuzz(constRegs, constMems, curBlock):
ret
=
[]
if
curBlock[
"startAddr"
]
in
runOnceBlock:
if
runOnceBlock[curBlock[
"startAddr"
]]
=
=
True
:
print
(
"run once block, return."
)
return
None
try
:
for
codeitem
in
curBlock[
"codes"
]:
if
testAsm(constRegs, constMems, codeitem)
=
=
False
:
regsRead
=
codeitem[
"regsRead"
]
regsWrite
=
codeitem[
"regsWrite"
]
operands
=
codeitem[
"operands"
]
if
ARM64_INS_CMP
=
=
codeitem[
"id"
]:
asmUniCmp(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
], codeitem[
"opTypes"
],
codeitem[
"operands"
])
elif
ARM64_INS_TST
=
=
codeitem[
"id"
]:
asmUniTst(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
], codeitem[
"opTypes"
],
codeitem[
"operands"
])
elif
ARM64_INS_B
=
=
codeitem[
"id"
]:
bret
=
asmUniB(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
], codeitem[
"opTypes"
],
codeitem[
"operands"
], codeitem[
"cc"
])
if
bret !
=
None
:
print
([
hex
(x)
for
x
in
bret])
if
len
(bret) >
1
:
runOnceBlock[curBlock[
"startAddr"
]]
=
True
env
=
{}
env[
"regs"
]
=
constRegs
env[
"mems"
]
=
constMems
env[
"nextAddr"
]
=
bret
ret.append(env)
return
ret
elif
ARM64_INS_CSEL
=
=
codeitem[
"id"
]:
dstRegId, srcRegIdList
=
asmUniCsel(constRegs,
int
(codeitem[
"addr"
],
16
), codeitem[
"bytes"
],
codeitem[
"opTypes"
], codeitem[
"operands"
])
if
len
(srcRegIdList) >
1
:
for
regId
in
srcRegIdList:
srcRegId
=
regId
cpyConstRegs
=
copy.deepcopy(constRegs)
writeReg(cpyConstRegs, dstRegId, readReg(cpyConstRegs, srcRegId))
env
=
{}
env[
"regs"
]
=
cpyConstRegs
env[
"mems"
]
=
constMems
env[
"nextAddr"
]
=
[
int
(codeitem[
"addr"
],
16
)
+
4
]
ret.append(env)
runOnceBlock[curBlock[
"startAddr"
]]
=
True
return
ret
else
:
print
(
"------------ only one result. -----------"
)
elif
ARM64_INS_RET
=
=
codeitem[
"id"
]:
return
None
else
:
print
(
"unknow ins."
)
if
getBlockNextAddr(curBlock)
=
=
None
:
print
(
"curBlock has not next block."
)
return
None
env
=
{}
env[
"regs"
]
=
constRegs
env[
"mems"
]
=
constMems
env[
"nextAddr"
]
=
getBlockNextAddr(curBlock)
ret.append(env)
return
ret
except
Exception as e:
print
(
repr
(e))
print
(traceback.format_exc())
return
None
virtualBlock
=
[
0x136e8
,
0x13774
,
0x1377c
,
0x13784
,
0x13794
,
0x137a4
,
0x136f0
,
0x136f8
,
0x137c4
,
0x138c4
,
0x138d4
,
0x13858
,
0x137cc
,
0x137d4
,
0x13884
,
0x13894
,
0x13810
,
0x13818
,
0x13820
,
0x13830
,
0x13854
,
0x138f8
,
0x13908
,
0x13960
,
0x138c0
,
0x13868
,
0x13870
,
0x13880
,
0x13700
,
0x13708
,
0x13a44
,
0x13718
,
0x13770
,
0x137e4
]
def
removeVirtualBlock(callStack):
for
item
in
range
(
len
(callStack)
-
1
,
-
1
,
-
1
):
for
addr
in
virtualBlock:
if
callStack[item]
=
=
addr:
del
callStack[item]
break
return
callStack
def
getBlockFeature(codeblock, blockAddr):
feature
=
""
if
blockAddr
in
codeblock:
curBlock
=
codeblock[blockAddr]
for
codeitem
in
curBlock[
"codes"
]:
feature
=
feature
+
codeitem[
"mnemonic"
]
+
codeitem[
"opTypes"
]
return
feature
def
testFuzzBlock(constRegs, constMems, codeblock, curBlock, callStack):
curConstRegs
=
copy.deepcopy(constRegs)
curConstMems
=
copy.deepcopy(constMems)
callStack.append(curBlock[
"startAddr"
])
endEnv
=
runFuzz(curConstRegs, curConstMems, curBlock)
if
endEnv
=
=
None
:
callStack
=
removeVirtualBlock(callStack)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-10-25 23:52
被lxcoder编辑
,原因: 增加样本附件
上传的附件: