-
-
[原创]Flare-On 8th Challenge 9复现
-
发表于: 2022-1-21 11:05 10541
-
这道题目可以好好看下官方WriteUp,其前半部分是Core Architecture Concepts——将题目中所用到的各种核心技术都进行了讲解,后半部分Challenge Walkthrough则是以题目作为前半部分技术的例子,对细节进行了阐述。这篇文章将侧重技术而并非解题。
笔者使用的VS版本如下:
进入main
函数之前的函数调用栈如下:
上图所示的栈回溯并不完整,完整调用关系如下:
重点在于_initterm_e
与_initterm
两个函数(摘自How to explicitly call CRT startup functions):
__xi_a
,__xi_z
,__xc_a
与__xc_z
含义如下(摘自How can I schedule some code to run after all '_atexit()' functions are completed):
微软在其文档中给出这样一段代码:
笔者编译时配置属性如下:
禁用优化:
可以看到生成之后在__xc_a
与__xc_z
中间有一_dynamic_initializer_for__gi__
指针:
题目中使用该技术进行VEH Hook,具体细节笔者会放到VEH Hooking一节中描述。关于该技术的利用,趋势科技在其博客中列出一表格如下:
文末会给出具体链接,感兴趣的读者可以进一步阅读。
VEH——Vectored Exception Handling,向量化异常处理。关于VEH与SEH知识讲解可以看VEH和SEH,这里不再赘述。
Vectored Exception Handling, Hooking Via Forced Exception这篇文章通过页的PAGE_GUARD属性触发VEH:
由于设置了pExceptionInfo->ContextRecord->EFlags |= 0x100
,每执行一条指令就会重新回到LeoHandler
。题目中__scrt_common_main_seh
函数在调用_initterm
时,会依次执行__xc_a
与__xc_z
之间每个函数:
我们先来看sub_402130
与sub_402150
两个函数:
sub_4054B0
根据传递参数获取指定API地址,其具体过程暂不作展开。sub_402130
通过给该函数传递值获取AddVectoredExceptionHandler
地址,之后由sub_402150
进行调用。跟进sub_406AD0
查看其功能:
进入异常处理的一种情况:
sub_406AD0
先是传递ContextRecord中ECX与EDX值给sub_4054B0
获取API地址,之后将该地址写入ContextRecord—>EAX中,最后更改ContextRecord->Eip + 3处指令以及EIP值:
另一种触发异常类似于下面形式:
上文提到sub_4054B0
函数会根据传递参数获取指定API地址,其接受两个参数——参数1用来指定DLL,参数2用来指定API。其获取DLL名称是通过搜索由sub_401100
函数建立起来的映射,该函数首先会解密DLL名称:
字符串第一个字符解密算法不同于其他字符,之后会为每个DLL名称赋予一个Key值。最终建立起来的映射如下:
其计算导出函数名称Hash值算法如下:
官方WriteUp在这里给了一个计算Hash值的脚本:
通过题目中算法计算输入DLL中每个导出函数名称的Hash值并保存至C Header文件,之后于File—>Load File—>Parse C Header File选择C Header文件,便可在Local Types窗口看到对应DLL的枚举类型:
分析时遇到Hash值直接选择对应enum即可:
wmsuper师傅在Flare-ON 8th 之第九题evil一文中采用的方法是获取需要修改的地址,对应DLL的Key及Hash值,之后再去对应DLL导出表中寻找匹配函数进行输出,最后通过得到的输出结果修复原题目对应地址处指令。
笔者在处理时采用了一个折衷的方案,之前在复现Challenge 7时使用了一个IDA Plugin——Shellcode Hashes,虽然其覆盖算法很多,但对于题目中这种特定算法没有在脚本当中实现,笔者于make_sc_hash_db.py
中添加了该算法:
之后生成数据库文件,使用插件时选择新生成数据库再应用对应算法即可:
关于该工具更多信息可阅读Using Precalculated String Hashes when Reverse Engineering Shellcode,make_sc_hash_db.py
脚本对DLL目录中每个DLL的所有导出函数应用脚本内所有Hash算法计算Hash值写入到数据库文件中:
官方WriteUp上给出了一个Nop题目中Anti-Disassembly指令的脚本:
再配合上nop-hidder脚本:
如此一来,使用IDA进行静态分析便会轻松很多。
关于Windows调试原理可以参阅:
Anti-Debug:
sub_4023D0
函数首先会PatchDbgBreakPoint
与DbgUiRemoteBreakin
两个函数:
通过Vmware使用的I/O端口0x5658进行检测:
如果是运行在Vmware中则直接退出:
之后的检测方法是来自Another VMWare Detection一文:
执行SELECT * FROM Win32_PnPEntity
以检测是否位于VirtualBox中(下面代码出自al-khaser):
IsDebuggerPresent
:
之后依次是CheckRemoteDebuggerPresent,NtGlobalFlag,SeDebugPrivilege,HardwareBreakpoints及GetTickCount相关Anti-Debug,具体实现可以参阅al-khaser及Anti-Debug:Timing,这里不再一一赘述。可以通过ScyllaHide进行Anti-Anti-Debug。
题目会校验传递参数个数:
之后sub_403A70
会调用sub_410EE0
函数(根据官方WriteUp,这里应该是使用了PolyHook2)HookCryptImportKey
:
解密字符串:
一共解密出4个字符串:"L0ve", "s3cret", "5Ex", "g0d"。笔者在这里没能动调,而是根据IDA静态分析结果计算而来,由于卡在此处故查到Flare-On 8 – Task 9一文,阅读过后发现其使用方法和工具都极高效,便不再重写这些步骤,感兴趣的读者可以跟着这篇文章学习一下。
typedef void (__cdecl
*
_PVFV)();
void _initterm(const _PVFV
*
ppfn, const _PVFV
*
end)
{
do
{
if
(_PVFV pfn
=
*
+
+
ppfn)
{
pfn();
}
}
while
(ppfn < end);
}
typedef
int
(__cdecl
*
_PIFV)();
int
_initterm_e(const _PIFV
*
ppfn, const _PIFV
*
end)
{
do
{
if
(_PIFV pfn
=
*
+
+
ppfn)
{
if
(
int
err
=
pfn())
return
err;
}
}
while
(ppfn < end);
return
0
;
}
typedef void (__cdecl
*
_PVFV)();
void _initterm(const _PVFV
*
ppfn, const _PVFV
*
end)
{
do
{
if
(_PVFV pfn
=
*
+
+
ppfn)
{
pfn();
}
}
while
(ppfn < end);
}
typedef
int
(__cdecl
*
_PIFV)();
int
_initterm_e(const _PIFV
*
ppfn, const _PIFV
*
end)
{
do
{
if
(_PIFV pfn
=
*
+
+
ppfn)
{
if
(
int
err
=
pfn())
return
err;
}
}
while
(ppfn < end);
return
0
;
}
extern _CRTALLOC(
".CRT$XIA"
) _PIFV __xi_a[];
extern _CRTALLOC(
".CRT$XIZ"
) _PIFV __xi_z[];
/
*
C initializers
*
/
extern _CRTALLOC(
".CRT$XCA"
) _PVFV __xc_a[];
extern _CRTALLOC(
".CRT$XCZ"
) _PVFV __xc_z[];
/
*
C
+
+
initializers
*
/
extern _CRTALLOC(
".CRT$XPA"
) _PVFV __xp_a[];
extern _CRTALLOC(
".CRT$XPZ"
) _PVFV __xp_z[];
/
*
C pre
-
terminators
*
/
extern _CRTALLOC(
".CRT$XTA"
) _PVFV __xt_a[];
extern _CRTALLOC(
".CRT$XTZ"
) _PVFV __xt_z[];
/
*
C terminators
*
/
extern _CRTALLOC(
".CRT$XIA"
) _PIFV __xi_a[];
extern _CRTALLOC(
".CRT$XIZ"
) _PIFV __xi_z[];
/
*
C initializers
*
/
extern _CRTALLOC(
".CRT$XCA"
) _PVFV __xc_a[];
extern _CRTALLOC(
".CRT$XCZ"
) _PVFV __xc_z[];
/
*
C
+
+
initializers
*
/
extern _CRTALLOC(
".CRT$XPA"
) _PVFV __xp_a[];
extern _CRTALLOC(
".CRT$XPZ"
) _PVFV __xp_z[];
/
*
C pre
-
terminators
*
/
extern _CRTALLOC(
".CRT$XTA"
) _PVFV __xt_a[];
extern _CRTALLOC(
".CRT$XTZ"
) _PVFV __xt_z[];
/
*
C terminators
*
/
int
func(void)
{
return
3
;
}
int
gi
=
func();
int
main()
{
return
gi;
}
int
func(void)
{
return
3
;
}
int
gi
=
func();
int
main()
{
return
gi;
}
bool
LeoHook::Hook(uintptr_t original_fun, uintptr_t hooked_fun)
{
LeoHook::og_fun
=
original_fun;
LeoHook::hk_fun
=
hooked_fun;
/
/
We cannot hook two functions
in
the same page, because we will cause an infinite callback
if
(AreInSamePage((const uint8_t
*
)og_fun, (const uint8_t
*
)hk_fun))
return
false;
/
/
Register the Custom Exception Handler
VEH_Handle
=
AddVectoredExceptionHandler(true, (PVECTORED_EXCEPTION_HANDLER)LeoHandler);
/
/
Toggle PAGE_GUARD flag on the page
if
(VEH_Handle && VirtualProtect((LPVOID)og_fun,
1
, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtection))
return
true;
return
false;
}
LONG
WINAPI LeoHook::LeoHandler(EXCEPTION_POINTERS
*
pExceptionInfo)
{
if
(pExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
STATUS_GUARD_PAGE_VIOLATION)
/
/
We will catch PAGE_GUARD Violation
{
if
(pExceptionInfo
-
>ContextRecord
-
>XIP
=
=
(uintptr_t)og_fun)
/
/
Make sure we are at the address we want within the page
{
pExceptionInfo
-
>ContextRecord
-
>XIP
=
(uintptr_t)hk_fun;
/
/
Modify EIP
/
RIP to where we want to jump to instead of the original function
}
pExceptionInfo
-
>ContextRecord
-
>EFlags |
=
0x100
;
/
/
Will trigger an STATUS_SINGLE_STEP exception right after the
next
instruction get executed. In short, we come right back into this exception handler
1
instruction later
return
EXCEPTION_CONTINUE_EXECUTION;
/
/
Continue to
next
instruction
}
if
(pExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
STATUS_SINGLE_STEP)
/
/
We will also catch STATUS_SINGLE_STEP, meaning we just had a PAGE_GUARD violation
{
DWORD dwOld;
VirtualProtect((LPVOID)og_fun,
1
, PAGE_EXECUTE_READ | PAGE_GUARD, &dwOld);
/
/
Reapply the PAGE_GUARD flag because everytime it
is
triggered, it get removes
return
EXCEPTION_CONTINUE_EXECUTION;
/
/
Continue the
next
instruction
}
return
EXCEPTION_CONTINUE_SEARCH;
/
/
Keep going down the exception handling
list
to find the right handler IF it
is
not
PAGE_GUARD nor SINGLE_STEP
}
bool
LeoHook::Hook(uintptr_t original_fun, uintptr_t hooked_fun)
{
LeoHook::og_fun
=
original_fun;
LeoHook::hk_fun
=
hooked_fun;
/
/
We cannot hook two functions
in
the same page, because we will cause an infinite callback
if
(AreInSamePage((const uint8_t
*
)og_fun, (const uint8_t
*
)hk_fun))
return
false;
/
/
Register the Custom Exception Handler
VEH_Handle
=
AddVectoredExceptionHandler(true, (PVECTORED_EXCEPTION_HANDLER)LeoHandler);
/
/
Toggle PAGE_GUARD flag on the page
if
(VEH_Handle && VirtualProtect((LPVOID)og_fun,
1
, PAGE_EXECUTE_READ | PAGE_GUARD, &oldProtection))
return
true;
return
false;
}
LONG
WINAPI LeoHook::LeoHandler(EXCEPTION_POINTERS
*
pExceptionInfo)
{
if
(pExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
STATUS_GUARD_PAGE_VIOLATION)
/
/
We will catch PAGE_GUARD Violation
{
if
(pExceptionInfo
-
>ContextRecord
-
>XIP
=
=
(uintptr_t)og_fun)
/
/
Make sure we are at the address we want within the page
{
pExceptionInfo
-
>ContextRecord
-
>XIP
=
(uintptr_t)hk_fun;
/
/
Modify EIP
/
RIP to where we want to jump to instead of the original function
}
pExceptionInfo
-
>ContextRecord
-
>EFlags |
=
0x100
;
/
/
Will trigger an STATUS_SINGLE_STEP exception right after the
next
instruction get executed. In short, we come right back into this exception handler
1
instruction later
return
EXCEPTION_CONTINUE_EXECUTION;
/
/
Continue to
next
instruction
}
if
(pExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
STATUS_SINGLE_STEP)
/
/
We will also catch STATUS_SINGLE_STEP, meaning we just had a PAGE_GUARD violation
{
DWORD dwOld;
VirtualProtect((LPVOID)og_fun,
1
, PAGE_EXECUTE_READ | PAGE_GUARD, &dwOld);
/
/
Reapply the PAGE_GUARD flag because everytime it
is
triggered, it get removes
return
EXCEPTION_CONTINUE_EXECUTION;
/
/
Continue the
next
instruction
}
return
EXCEPTION_CONTINUE_SEARCH;
/
/
Keep going down the exception handling
list
to find the right handler IF it
is
not
PAGE_GUARD nor SINGLE_STEP
}
sub_402130 proc near
mov edx,
542F881Eh
mov ecx,
246132h
call GetProcAddr
mov dword_6D16E4, eax
retn
sub_402130 endp
sub_402150 proc near
push offset sub_406AD0
push
1
call dword_6D16E4
retn
sub_402150 endp
sub_402130 proc near
mov edx,
542F881Eh
mov ecx,
246132h
call GetProcAddr
mov dword_6D16E4, eax
retn
sub_402130 endp
sub_402150 proc near
push offset sub_406AD0
push
1
call dword_6D16E4
retn
sub_402150 endp
0x176684
ntdll.dll
0x246132
kernel32.dll
0x052325
ws2_32.dll
0x234324
user32.dll
0x523422
advapi32.dll
0x43493856
gdi32.dll
0x4258672
ole32.dll
0x7468951
oleaut32.dll
0x176684
ntdll.dll
0x246132
kernel32.dll
0x052325
ws2_32.dll
0x234324
user32.dll
0x523422
advapi32.dll
0x43493856
gdi32.dll
0x4258672
ole32.dll
0x7468951
oleaut32.dll
import
pefile
import
sys
import
os
M32
=
0xffffffff
def
main():
if
len
(sys.argv) !
=
3
:
print
(
"usage: generate_hashes <in.dll> <out.hashes>"
)
sys.exit(
0
)
d
=
[pefile.DIRECTORY_ENTRY[
"IMAGE_DIRECTORY_ENTRY_EXPORT"
]]
pe
=
pefile.PE(sys.argv[
1
], fast_load
=
True
)
pe.parse_data_directories(directories
=
d)
names
=
[ e.name
for
e
in
pe.DIRECTORY_ENTRY_EXPORT.symbols]
names
=
[i
for
i
in
names
if
i]
with
open
(sys.argv[
2
],
'wb'
) as f:
f.write(b
"enum %s_hash\n"
%
os.path.split(sys.argv[
1
])[
-
1
].split(
'.'
)[
0
].encode())
f.write(b
"{\n"
)
for
name
in
sorted
(names):
h
=
0x40
for
x
in
name:
h
=
x
-
0x45523f21
*
h & M32
f.write((b
" %s = 0x%x,\n"
%
(name, h)))
f.write(b
"};"
)
if
__name__
=
=
'__main__'
:
main()
import
pefile
import
sys
import
os
M32
=
0xffffffff
def
main():
if
len
(sys.argv) !
=
3
:
print
(
"usage: generate_hashes <in.dll> <out.hashes>"
)
sys.exit(
0
)
d
=
[pefile.DIRECTORY_ENTRY[
"IMAGE_DIRECTORY_ENTRY_EXPORT"
]]
pe
=
pefile.PE(sys.argv[
1
], fast_load
=
True
)
pe.parse_data_directories(directories
=
d)
names
=
[ e.name
for
e
in
pe.DIRECTORY_ENTRY_EXPORT.symbols]
names
=
[i
for
i
in
names
if
i]
with
open
(sys.argv[
2
],
'wb'
) as f:
f.write(b
"enum %s_hash\n"
%
os.path.split(sys.argv[
1
])[
-
1
].split(
'.'
)[
0
].encode())
f.write(b
"{\n"
)
for
name
in
sorted
(names):
h
=
0x40
for
x
in
name:
h
=
x
-
0x45523f21
*
h & M32
f.write((b
" %s = 0x%x,\n"
%
(name, h)))
f.write(b
"};"
)
if
__name__
=
=
'__main__'
:
main()
def
imul45523f21hSub(inString,fName):
if
inString
is
None
:
return
0
val
=
0x40
for
i
in
inString:
val
=
val
*
0x45523f21
val
=
i
-
val
val
=
val &
0xFFFFFFFF
val
=
val &
0xFFFFFFFF
return
val
pseudocode_imul45523f21hSub
=
'''acc := 0x40;
for c in input_string {
acc := acc * 45523f21h:
acc := c -acc;
}
'''
......
# The list of tuples of (supported hash name, hash size, pseudo_code)
HASH_TYPES
=
[
(
'ror7AddHash32'
,
32
, pseudocode_ror7AddHash32),
(
'ror9AddHash32'
,
32
, pseudocode_ror9AddHash32),
(
'ror11AddHash32'
,
32
, pseudocode_ror11AddHash32),
(
'ror13AddHash32'
,
32
, pseudocode_ror13AddHash32),
(
'ror13AddWithNullHash32'
,
32
, pseudocode_ror13AddWithNullHash32),
(
'ror13AddHash32AddDll'
,
32
, pseudocode_ror13AddHash32AddDll),
(
'ror13AddHash32DllSimple'
,
32
, pseudocode_ror13AddHash32DllSimple),
(
'ror13AddHash32Sub20h'
,
32
, pseudocode_ror13AddHash32Sub20h),
(
'ror13AddHash32Sub1'
,
32
, pseudocode_ror13AddHash32),
(
'addRor4WithNullHash32'
,
32
, pseudocode_addRor4WithNullHash32),
(
'addRor13Hash32'
,
32
, pseudocode_addRor13Hash32),
(
'addRor13HashOncemore32'
,
32
, pseudocode_addRor13HashOncemore32),
(
'rol3XorEax'
,
32
, pseudocode_rol3XorEax),
(
'rol3XorHash32'
,
32
, pseudocode_rol3XorHash32),
(
'rol5AddHash32'
,
32
, pseudocode_rol5AddHash32),
(
'addRol5HashOncemore32'
,
32
, pseudocode_addRol5HashOncemore32),
(
'rol7AddHash32'
,
32
, pseudocode_rol7AddHash32),
(
'rol7AddXor2Hash32'
,
32
, pseudocode_rol7AddXor2Hash32),
(
'rol7XorHash32'
,
32
, pseudocode_rol7XorHash32),
(
'rol5XorHash32'
,
32
, pseudocode_rol5XorHash32),
(
'rol8Xor0xB0D4D06Hash32'
,
32
, pseudocode_rol8Xor0xB0D4D06Hash32),
(
'chAddRol8Hash32'
,
32
, pseudocode_chAddRol8Hash32),
(
'rol9AddHash32'
,
32
, pseudocode_rol9AddHash32),
(
'rol9XorHash32'
,
32
, pseudocode_rol9XorHash32),
(
'xorRol9Hash32'
,
32
, pseudocode_xorRol9Hash32),
(
'shl7Shr19XorHash32'
,
32
, pseudocode_shl7Shr19XorHash32),
(
'shl7Shr19AddHash32'
,
32
, pseudocode_shl7Shr19AddHash32),
(
'shl7SubHash32DoublePulser'
,
32
, pseudocode_shl7SubHash32DoublePulser),
(
'sll1AddHash32'
,
32
, pseudocode_sll1AddHash32),
(
'shr2Shl5XorHash32'
,
32
, pseudocode_shr2Shl5XorHash32),
(
'xorShr8Hash32'
,
32
, pseudocode_xorShr8Hash32),
(
'imul83hAdd'
,
32
, pseudocode_imul83hAdd),
(
'imul21hAddHash32'
,
32
, pseudocode_imul21hAddHash32),
(
'or21hXorRor11Hash32'
,
32
, pseudocode_or21hXorRor11Hash32),
(
'or23hXorRor17Hash32'
,
32
, pseudocode_or23hXorRor17Hash32),
(
'playWith0xe8677835Hash'
,
32
, pseudocode_playWith0xe8677835Hash),
(
'poisonIvyHash'
,
32
, pseudocode_poisonIvyHash),
(
'crc32'
,
32
,
'Standard crc32'
),
(
'crc32Xor0xca9d4d4e'
,
32
,
'crc32 ^ 0xCA9D4D4E'
),
(
'crc32bzip2lower'
,
32
,
'crc32 bzip2 and str lower'
),
(
'mult21AddHash32'
,
32
, pseudocode_hashMult21),
(
'add1505Shl5Hash32'
,
32
, pseudocode_add1505Shl5Hash32),
(
'dualaccModFFF1Hash'
,
32
, pseudocode_dualaccModFFF1Hash),
(
'hash_Carbanak'
,
32
, pseudocode_hash_Carbanak),
(
'hash_ror13AddUpperDllnameHash32'
,
32
, pseudocode_hash_ror13AddUpperDllnameHash32),
(
'fnv1Xor67f'
,
32
, pseudocode_fnv1Xor67f),
(
'adler32_666'
,
32
,
'Adler32 with starting value 666'
),
(
'shift0x82F63B78'
,
32
,
'like crc32c'
),
(
'contiApiHashing'
,
32
, pseudocode_contiApiHashing),
(
'fnv1'
,
32
, pseudocode_fnv1),
(
'imul45523f21hSub'
,
32
, pseudocode_imul45523f21hSub)
]
def
imul45523f21hSub(inString,fName):
if
inString
is
None
:
return
0
val
=
0x40
for
i
in
inString:
val
=
val
*
0x45523f21
val
=
i
-
val
val
=
val &
0xFFFFFFFF
val
=
val &
0xFFFFFFFF
return
val
pseudocode_imul45523f21hSub
=
'''acc := 0x40;
for c in input_string {
acc := acc * 45523f21h:
acc := c -acc;
}
'''
......
# The list of tuples of (supported hash name, hash size, pseudo_code)
HASH_TYPES
=
[
(
'ror7AddHash32'
,
32
, pseudocode_ror7AddHash32),
(
'ror9AddHash32'
,
32
, pseudocode_ror9AddHash32),
(
'ror11AddHash32'
,
32
, pseudocode_ror11AddHash32),
(
'ror13AddHash32'
,
32
, pseudocode_ror13AddHash32),
(
'ror13AddWithNullHash32'
,
32
, pseudocode_ror13AddWithNullHash32),
(
'ror13AddHash32AddDll'
,
32
, pseudocode_ror13AddHash32AddDll),
(
'ror13AddHash32DllSimple'
,
32
, pseudocode_ror13AddHash32DllSimple),
(
'ror13AddHash32Sub20h'
,
32
, pseudocode_ror13AddHash32Sub20h),
(
'ror13AddHash32Sub1'
,
32
, pseudocode_ror13AddHash32),
(
'addRor4WithNullHash32'
,
32
, pseudocode_addRor4WithNullHash32),
(
'addRor13Hash32'
,
32
, pseudocode_addRor13Hash32),
(
'addRor13HashOncemore32'
,
32
, pseudocode_addRor13HashOncemore32),
(
'rol3XorEax'
,
32
, pseudocode_rol3XorEax),
(
'rol3XorHash32'
,
32
, pseudocode_rol3XorHash32),
(
'rol5AddHash32'
,
32
, pseudocode_rol5AddHash32),
(
'addRol5HashOncemore32'
,
32
, pseudocode_addRol5HashOncemore32),
(
'rol7AddHash32'
,
32
, pseudocode_rol7AddHash32),
(
'rol7AddXor2Hash32'
,
32
, pseudocode_rol7AddXor2Hash32),
(
'rol7XorHash32'
,
32
, pseudocode_rol7XorHash32),
(
'rol5XorHash32'
,
32
, pseudocode_rol5XorHash32),
(
'rol8Xor0xB0D4D06Hash32'
,
32
, pseudocode_rol8Xor0xB0D4D06Hash32),
(
'chAddRol8Hash32'
,
32
, pseudocode_chAddRol8Hash32),
(
'rol9AddHash32'
,
32
, pseudocode_rol9AddHash32),
(
'rol9XorHash32'
,
32
, pseudocode_rol9XorHash32),
(
'xorRol9Hash32'
,
32
, pseudocode_xorRol9Hash32),
(
'shl7Shr19XorHash32'
,
32
, pseudocode_shl7Shr19XorHash32),
(
'shl7Shr19AddHash32'
,
32
, pseudocode_shl7Shr19AddHash32),
(
'shl7SubHash32DoublePulser'
,
32
, pseudocode_shl7SubHash32DoublePulser),
(
'sll1AddHash32'
,
32
, pseudocode_sll1AddHash32),
(
'shr2Shl5XorHash32'
,
32
, pseudocode_shr2Shl5XorHash32),
(
'xorShr8Hash32'
,
32
, pseudocode_xorShr8Hash32),
(
'imul83hAdd'
,
32
, pseudocode_imul83hAdd),
(
'imul21hAddHash32'
,
32
, pseudocode_imul21hAddHash32),
(
'or21hXorRor11Hash32'
,
32
, pseudocode_or21hXorRor11Hash32),
(
'or23hXorRor17Hash32'
,
32
, pseudocode_or23hXorRor17Hash32),
(
'playWith0xe8677835Hash'
,
32
, pseudocode_playWith0xe8677835Hash),
(
'poisonIvyHash'
,
32
, pseudocode_poisonIvyHash),
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)