原创 KCTF 看雪学院
出题团队简介
崇文路大专是一个隶属于重庆邮电大学信息安全协会的CTF战队,其主要目标是培养对信息安全感兴趣的学弟学妹们,带着新入门的成员一起参加比赛,致力于夺得各大比赛签到题一血。同时也是重庆邮电大学信息安全协会旗下的0xFA战队的附属战队,0xFA战队曾多次进入XCTF线下总决赛、安洵杯线下总决赛、国赛总决赛。
专家点评
赛题设计思路
原创混淆器
解题思路
赛题解析
本赛题解析由看雪论坛 KuCha128 给出:
0x00 简单分析
push rax
push rax
pushfq
call $+5
pop rax
xor rax,D1E15
mov qword ptr ss:[rsp+10],rax
popfq
pop rax
ret
push rax
push rax
pushfq
push rax
push rax
pushfq
call $+5
pop rax
xor rax, 0xE4EB3
mov qword ptr ss:[rsp+0x10], rax
popfq
pop rax
pop rax
add rax, 0x8242E
mov qword ptr ss:[rsp+0x10], rax
popfq
pop rax
ret
push rdx
push rdx
pop rdx
pop rdx
push rcx
push rdx
pop rdx
push rbx
pop rbx
pop rcx
push rax
push rax
pushfq
push rax
push rax
pushfq
call $+5
pop rax
xor rax, 0xDC85F
mov qword ptr ss:[rsp+0x10], rax
popfq
pop rax
pop rax
add rax, 0x51438
mov qword ptr ss:[rsp+0x10], rax
popfq
pop rax
jmp 0x00000001400979D6
0x01 优化题目的混淆
static uintptr_t g_nFileSize = 0;
static LPBYTE g_lpFileBuffer = 0;
void ReadPEFile()
{
HANDLE hFile = NULL;
HANDLE hMapFile = NULL;
LPBYTE lpFileBuffer = NULL;
hFile = CreateFileA("D:\\Projects\\KCTF2021Spring\\CrackNote\\6\\KCTF.exe", // open MYFILE.TXT
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "Could not create file." << std::endl;
goto EXIT_PROC;
}
g_nFileSize = GetFileSize(hFile, NULL);
if (g_nFileSize == INVALID_FILE_SIZE)
{
std::cout << "GetFileSize error." << std::endl;
goto EXIT_PROC;
}
hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READONLY,
0, 0, NULL);
if (hMapFile == NULL)
{
std::cout << "Could not create file-mapping object." << std::endl;
goto EXIT_PROC;
}
lpFileBuffer = (LPBYTE)MapViewOfFile(hMapFile, // Handle to mapping object.
FILE_MAP_READ, // Read/write permission
0, // Max. object size.
0, // Size of hFile.
0); // Map entire file.
if (lpFileBuffer == NULL)
{
std::cout << "MapViewOfFile error." << std::endl;
goto EXIT_PROC;
}
g_lpFileBuffer = new BYTE[g_nFileSize + 0x100000000];
g_lpFileBuffer = (LPBYTE)(((QWORD)g_lpFileBuffer & 0xFFFFFFFF00000000) + 0x100000000);
if (g_lpFileBuffer == NULL)
{
std::cout << "Alloc error." << std::endl;
goto EXIT_PROC;
}
memcpy(g_lpFileBuffer, lpFileBuffer, g_nFileSize);
EXIT_PROC:
if (lpFileBuffer != NULL)
{
UnmapViewOfFile(lpFileBuffer);
lpFileBuffer = NULL;
}
if (hMapFile != NULL)
{
CloseHandle(hMapFile);
hMapFile = NULL;
}
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
}
void AntiObfuscation1()
{
LPBYTE lpStart = 0;
LPBYTE lpEnd = 0;
DWORD dwCount = 0;
//.text节
lpStart = g_lpFileBuffer+0x400;
lpEnd = lpStart + 0x3000;
dwCount = 0;
while (true)
{
//50509CE800000000584835????????48894424109D58C3
LPBYTE lpResult = (LPBYTE)FindHexBytes(lpStart, lpEnd, "50509CE800000000584835????????48894424109D58C3");
if (lpResult == (LPVOID)-1) {
break;
}
else {
dwCount++;
lpStart = lpResult + 1;
QWORD dwFindFA = (QWORD)lpResult;
QWORD dwFindVA = dwFindFA - 0x400 + 0x1000;
QWORD dwCallNextFA = (QWORD)lpResult + 8;
QWORD dwCallNextVA = dwCallNextFA - 0x400 + 0x1000 ;// 修复内存地址
QWORD dwXor = Mem_RDword(lpResult + 11);
QWORD dwNextAddrVA = dwXor ^ dwCallNextVA;
QWORD dwNextAddrFA = 0;
BYTE aryNop[25] = {
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
};
//混淆方案1的opcode size 固定是23
Mem_WBytes2((LPVOID)dwFindFA, aryNop, 23);
BYTE bHook[] = { 0xE9, 00, 00, 00, 00 };
Mem_WDword(bHook + 1, (DWORD)(dwNextAddrVA - dwFindVA - 5));
Mem_WBytes2((LPVOID)dwFindFA, bHook, 5);
}
}
D("patch .text %d addr", dwCount);
//.cop节
lpStart = g_lpFileBuffer + 0x6200;
lpEnd = lpStart + 0xF0000;
dwCount = 0;
while (true)
{
//50509CE800000000584835????????48894424109D58C3
LPBYTE lpResult = (LPBYTE)FindHexBytes(lpStart, lpEnd, "50509CE800000000584835????????48894424109D58C3");
if (lpResult == (LPVOID)-1) {
break;
}
else {
dwCount++;
lpStart = lpResult + 1;
QWORD dwFindFA = (QWORD)lpResult;
QWORD dwFindVA = dwFindFA - 0x6200 + 0xB000;
QWORD dwCallNextFA = (QWORD)lpResult + 8;
QWORD dwCallNextVA = dwCallNextFA - 0x6200 + 0xB000;// 修复内存地址
QWORD dwXor = Mem_RDword(lpResult + 11);
QWORD dwNextAddrVA = dwXor ^ dwCallNextVA;
QWORD dwNextAddrFA = 0;
BYTE aryNop[25] = {
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90,
};
//混淆方案1的opcode size 固定是23
Mem_WBytes2((LPVOID)dwFindFA, aryNop, 23);
BYTE bHook[] = { 0xE9, 00, 00, 00, 00 };
Mem_WDword(bHook + 1, (DWORD)(dwNextAddrVA - dwFindVA - 5));
Mem_WBytes2((LPVOID)dwFindFA, bHook, 5);
}
}
D("patch .cop %d addr", dwCount);
}
a = editor.getText()
lst=a.split("\n")
lstdel=[]
for index in range(len(lst)-18):
#for index in range(20):
i1=lst[index][-8:]
i2=lst[index+1][-8:]
i3=lst[index+2][-6:]
i17=lst[index+17][-3:]
#print(i1,i2,i3,i17)
if(i1=="push rax" and i2=="push rax" and i3=="pushfq" and i17=="ret"):
eva=lst[index][:18]
cnva=lst[index+7][:18]
xi=lst[index+8].rfind(" ");
x=lst[index+8][xi:]
ai=lst[index+13].rfind(" ");
a=lst[index+13][ai:]
print(eva, cnva, x, a)
print("finish.")
LPCSTR g_aryFix[] = {
"0x00000001400B5E68", "0x000000014007FBD8", "0x6665", "0x36F74",
"0x000000014005AF49", "0x000000014002BB97", "0x28376", "0xCFCD7",
"0x00000001400E05AD", "0x0000000140040B81", "0xD7FA9", "0xFFFFFFFFFFFE178B",
"0x000000014000151A", "0x000000014008F26F", "0xDB257", "0x78C45",
"0x0000000140029C72", "0x000000014008F92C", "0xEB504", "0x328B9",
"0x000000014001E0A6", "0x00000001400F1BA1", "0x6545B", "0x28976",
"0x0000000140052153", "0x0000000140012134", "0x485D5", "0xFFFFFFFFFFFF07DE",
"0x0000000140083D5A", "0x000000014000F6CA", "0x43749", "0x46ACE",
"0x000000014002C47E", "0x00000001400C2EFA", "0xA5AD1", "0x89CB0",
"0x00000001400E7AEC", "0x00000001400370EC", "0xFEA16", "0xFFFFFFFFFFFD4BAC",
"0x00000001400C0C09", "0x00000001400F44A9", "0x2F746", "0xFFFFFFFFFFF323E7",
"0x000000014001533A", "0x0000000140020B70", "0x15CD7", "0x5E0A2",
"0x00000001400572A6", "0x0000000140059016", "0xFBD1", "0xFFFFFFFFFFFDF0F0",
"0x0000000140022F8A", "0x00000001400767A4", "0x4BE4C", "0x88F4",
//... ...
};
void AntiObfuscation2()
{
for (int i = 0; i < sizeof(g_aryFix) / sizeof(g_aryFix[0]) / 4 ;i++)
{
QWORD dwFindRVA = strtoull(g_aryFix[i * 4 ], 0, 16) - 0x140000000;
QWORD dwFindFA = 0;
if (dwFindRVA < 0x3400)
{
dwFindFA = (QWORD)g_lpFileBuffer + dwFindRVA - 0x1000 + 0x400;
}
else
{
dwFindFA = (QWORD)g_lpFileBuffer + dwFindRVA - 0xB000 + 0x6200;
}
QWORD dwCallNextRVA= strtoull(g_aryFix[i * 4+1], 0, 16) - 0x140000000;
QWORD dwXor = strtoull(g_aryFix[i * 4 + 2], 0, 16);
QWORD dwAdd = strtoull(g_aryFix[i * 4 + 3], 0, 16);
QWORD dwNextAddrRVA = (dwXor ^ dwCallNextRVA) + dwAdd;
BYTE bHook[] = { 0xE9, 00, 00, 00, 00 };
Mem_WDword(bHook + 1, (DWORD)(dwNextAddrRVA - dwFindRVA - 5));
Mem_WBytes2((LPVOID)dwFindFA, bHook, 5);
}
}
a = editor.getText()
lst=a.split("\n")
print(len(lst));
lstdel=[]
for index in range(len(lst)):
if(lst[index][-22:-19] == "jmp"):
lstdel.append(index)
lstdel.reverse()
print(len(lstdel))
for index in range(len(lstdel)):
del lst[lstdel[index]]
for fxcktime in range(10):
lstdel=[]
for index in range(len(lst)-1):
i1=lst[index][-8:-4]
i2=lst[index+1][-7:-4]
reg1=lst[index][-3:]
reg2=lst[index+1][-3:]
if(i1=="push" and i2=="pop" and reg1==reg2):
#print(i1,reg1,i2,reg2)
lstdel.append(index)
lstdel.append(index+1)
lstdel.reverse()
for index in range(len(lstdel)):
del lst[lstdel[index]]
fo=open("D:\\Projects\\KCTF2021Spring\\CrackNote\\6\\crack\\crack\\pyoutput.txt","w")
for index in range(len(lst)):
fo.write(lst[index]+"\n")
fo.close()
print("finish.");
push addr+ret = jmp addr
push addr1+jmp addr2= call addr2 (addr1是call的返回地址)
a = editor.getText()
lst=a.split("\n")
lstdel=[]
for index in range(len(lst)-18):
i1=lst[index][-8:]
i2=lst[index+1][-8:]
i3=lst[index+2][-6:]
i17=lst[index+16][-7:]
#print(i1,i2,i3,i17)
if(i1=="push rax" and i2=="push rax" and i3=="pushfq" and i17=="pop rax"):
eva=lst[index][:18]
cnva=lst[index+7][:18]
callva=lst[index+17][:18]
xi=lst[index+8].rfind(" ");
x=lst[index+8][xi:]
ai=lst[index+13].rfind(" ");
a=lst[index+13][ai:]
print(eva, cnva, x, a, callva)
print("finish.")
LPCSTR g_aryFixC[] = {
"0x000000014007A4C4", "0x0000000140089E51", "0xDC85F", "0x51438", "0x00000001400979D8",
"0x00000001400ADE90", "0x00000001400D4AEB", "0x4E2ED", "0xFFFFFFFFFFFD199D", "0x0000000140060882",
"0x00000001400C4678", "0x0000000140020DE5", "0xD2FE3", "0xFFFFFFFFFFFBE04E", "0x000000014005CC6E",
"0x00000001400C673D", "0x00000001400E7B10", "0xEB97C", "0x6DDA4", "0x000000014003F7D0",
"0x000000014003AF3E", "0x00000001400DDF75", "0x9704D", "0xFFFFFFFFFFFF5B08", "0x000000014003F7D0",
"0x00000001400839E3", "0x000000014007BECA", "0x36372", "0xA777F", "0x00000001400F90F3",
"0x00000001400543F0", "0x00000001400A164B", "0xAF7C5", "0x5CDEC", "0x0000000140078E09",
"0x00000001400998CB", "0x00000001400B928A", "0x2C92F", "0xE4AC", "0x00000001400D031B",
"0x000000014007C0AC", "0x000000014009B414", "0xC2AD8", "0xFFFFFFFFFFFC7598", "0x00000001400D42F1",
"0x000000014008FBE2", "0x0000000140047E12", "0x56408", "0x65F02", "0x00000001400728A0",
"0x000000014006B5D5", "0x00000001400194CA", "0x78E10", "0x3996", "0x0000000140078E09",
"0x0000000140077920", "0x00000001400A2374", "0x4FE21", "0xFFFFFFFFFFFCEA1A", "0x0000000140039068",
"0x00000001400943F5", "0x000000014008595F", "0xF3ADF", "0xFFFFFFFFFFFA3AAE", "0x00000001400DFCB3",
"0x000000014003768E", "0x000000014005087F", "0x45B11", "0xAB445", "0x000000014002650B",
//... ...
};
void AntiObfuscation3()
{
for (int i = 0; i < sizeof(g_aryFixC) / sizeof(g_aryFixC[0]) / 5; i++)
{
QWORD dwFindRVA = strtoull(g_aryFixC[i * 5], 0, 16) - 0x140000000;
QWORD dwFindFA = 0;
if (dwFindRVA < 0x3400)
{
dwFindFA = (QWORD)g_lpFileBuffer + dwFindRVA - 0x1000 + 0x400;
}
else
{
dwFindFA = (QWORD)g_lpFileBuffer + dwFindRVA - 0xB000 + 0x6200;
}
QWORD dwCallNextRVA = strtoull(g_aryFixC[i * 5 + 1], 0, 16) - 0x140000000;
QWORD dwXor = strtoull(g_aryFixC[i * 5 + 2], 0, 16);
QWORD dwAdd = strtoull(g_aryFixC[i * 5 + 3], 0, 16);
QWORD dwReturnRVA = (dwXor ^ dwCallNextRVA) + dwAdd;
QWORD dwCallRVA= strtoull(g_aryFixC[i * 5+4], 0, 16) - 0x140000000;
QWORD dwHookRVA = dwReturnRVA - 5 ;
QWORD dwHookFA = 0;
if (dwHookRVA < 0x3400)
{
dwHookFA = (QWORD)g_lpFileBuffer + dwHookRVA - 0x1000 + 0x400;
}
else
{
dwHookFA = (QWORD)g_lpFileBuffer + dwHookRVA - 0xB000 + 0x6200;
}
//BYTE nop[] = { 0x90,0x90,0x90,0x90,0x90 };
//if (memcmp((LPBYTE)dwHookFA, nop, 5) != 0)
//{
// printf("5 nops is not found.\r\n");
//}
BYTE bHook[] = { 0xE9, 00, 00, 00, 00 };
Mem_WDword(bHook + 1, (DWORD)(dwHookRVA - dwFindRVA - 5));
Mem_WBytes2((LPVOID)dwFindFA, bHook, 5);
BYTE bHook2[] = { 0xE8, 00, 00, 00, 00 };
Mem_WDword(bHook2 + 1, (DWORD)(dwCallRVA - dwHookRVA - 5));
Mem_WBytes2((LPVOID)dwHookFA, bHook2, 5);
}
}
0x02 分析程序的验证逻辑
0x0000000140071DE0 sub rsp, 0x28
0x00000001400A6A41 call 0x00000001400979D8
0x000000014000B2EA add rsp, 0x28
0x0000000140066D1D jmp 0x00000001400F4594
0x00000001400F4596 mov qword ptr ss:[rsp+0x8], rbx
0x00000001400574EC mov qword ptr ss:[rsp+0x10], rsi
0x000000014003AE64 push rdi
0x00000001400339F9 sub rsp, 0x30
0x00000001400B5EDB mov ecx, 0x1
0x000000014006C19E call 0x0000000140060882
0x0000000140052C16 test al, al
0x000000014002C7AC je 0x000000014002C7C5
0x00000001400FA123 xor sil, sil
0x00000001400503B8 mov byte ptr ss:[rsp+0x20], sil
0x00000001400F5532 call 0x00000001400F90F3
0x000000014005EB9A mov bl, al
0x000000014003B118 mov ecx, dword ptr ds:[0x00000001400066A0]
0x0000000140082181 cmp ecx, 0x1
0x00000001400F4B13 je 0x00000001400F4B2C
0x0000000140044567 test ecx, ecx
0x000000014000E80D jne 0x000000014000E826
0x000000014001938F mov dword ptr ds:[0x00000001400066A0], 0x1
0x00000001400768A6 lea rdx, ds:[0x0000000140004658]
0x00000001400D8E77 lea rcx, ds:[0x0000000140004640]
0x00000001400A404C call 0x00000001400D031B
0x000000014001A610 test eax, eax
0x00000001400BF926 je 0x00000001400BF93F
0x00000001400BBCE9 lea rdx, ds:[0x0000000140004638]
0x000000014003E227 lea rcx, ds:[0x0000000140004620]
0x000000014002145F call 0x00000001400D42F1
0x000000014007CF86 mov dword ptr ds:[0x00000001400066A0], 0x2
0x000000014004C6F2 mov cl, bl
0x0000000140077917 call 0x00000001400728A0
0x00000001400BC76A call 0x0000000140039068
0x0000000140046F51 mov rbx, rax
0x00000001400E073E cmp qword ptr ds:[rax], 0x0
0x00000001400A2DD5 je 0x00000001400A2DEE
0x0000000140019E29 call 0x00000001400DFCB3
0x0000000140019E30 mov rbx, rax
0x00000001400C7DA6 cmp qword ptr ds:[rax], 0x0
0x000000014007A883 je 0x000000014007A89C
0x00000001400C07AE call 0x000000014002650B ;_get_initial_narrow_environment
0x000000014008E432 mov rdi, rax
0x0000000140041D1A call 0x00000001400EED90 ;__p___argv
0x0000000140041D23 mov rbx, qword ptr ds:[rax]
0x0000000140088748 call 0x0000000140068129 ;__p___argc
0x0000000140092400 mov r8, rdi
0x000000014003D3AC mov rdx, rbx
0x0000000140059887 mov ecx, dword ptr ds:[rax]
0x00000001400A313B call 0x0000000140083814 ;main
0x0000000140083333 cmp rax, 0x54
0x0000000140035698 je 0x00000001400356B1
;输出错误提示
0x0000000140048E00 lea rcx, ds:[0x000000014000449C]
0x0000000140089A5C call 0x00000001400CD482
0x00000001400356B1 ....
0x0000000140064B92 xor edx, edx
0x0000000140013BE4 lea rax, ss:[rsp+0xEC0]
0x000000014002469D mov rcx, rax
0x000000014004DA5D mov r8d, 0x150
0x000000014007C4C8 call 0x00000001400C2EA1 ;memset
QWORD ary[42] = {0};
;循环遍历输入的flag
0x00000001400462B9 mov qword ptr ss:[rsp+0xA8], 0x0 ;循环变量
0x0000000140054381 cmp qword ptr ss:[rsp+0xA8], 0x2A ;循环次数=0x2A
0x000000014001603F jge 0x0000000140016058
0x0000000140036738 lea rax, ss:[rsp+0x1010]
0x00000001400B433E mov rcx, qword ptr ss:[rsp+0xA8]
0x00000001400F7366 shl rcx, 0x1
0x00000001400F9958 add rax, rcx
0x00000001400F5555 mov rcx, rax
0x0000000140014AC7 call 0x0000000140018FA3 ;计算数值
0x0000000140014ACC mov rcx, qword ptr ss:[rsp+0xA8]
0x00000001400787FE mov qword ptr ss:[rsp+rcx*8+0xEC0], rax ;写入数组
0x00000001400AFE42 cmp qword ptr ss:[rsp+0xA8], 0x0
0x0000000140022C16 je 0x0000000140022C2F
0x00000001400297BA mov rax, qword ptr ss:[rsp+0xA8]
0x00000001400BCBD3 add rax, 0x1 ;循环变量+=1
0x000000014007F965 mov qword ptr ss:[rsp+0xA8], rax
0x0000000140054381 cmp qword ptr ss:[rsp+0xA8], 0x2A
0x000000014001603F jge 0x0000000140016058
;...进入下一次循环
;计算数值函数
0x000000014005828F sub rsp, 0x38
0x00000001400AB750 mov qword ptr ss:[rsp+0x30], rcx
0x00000001400466C5 mov rax, qword ptr ss:[rsp+0x30]
0x000000014003423A mov cl, byte ptr ds:[rax]
0x0000000140048352 call 0x00000001400706B9 ;字符转数字
0x00000001400BA991 imul rax, rax, 0x2A
0x00000001400EA00D mov rdx, qword ptr ss:[rsp+0x30]
0x0000000140039BC9 mov cl, byte ptr ds:[rdx+0x1]
0x000000014005C2D0 mov qword ptr ss:[rsp+0x28], rax
0x000000014008807A call 0x0000000140087B21 ;字符转数字
0x0000000140037CF1 mov rdx, qword ptr ss:[rsp+0x28]
0x00000001400A7DF8 add rdx, rax
0x00000001400D4395 mov rax, rdx
0x0000000140057C71 add rsp, 0x38
0x00000001400DA66E ret
;字符转数字函数(部分)
0x00000001400D5E04 sub rsp, 0x10
0x00000001400731D7 mov byte ptr ss:[rsp+0x7], cl
0x00000001400882CA movsx eax, byte ptr ss:[rsp+0x7]
0x00000001400938D7 cmp eax, 0x30
0x000000014009A8BF jl 0x000000014009A8D8
0x00000001400B54F4 movsx eax, byte ptr ss:[rsp+0x7]
0x000000014001A372 cmp eax, 0x39 ;'9'
0x00000001400794C2 jg 0x00000001400794DB
0x0000000140043279 movsx rax, byte ptr ss:[rsp+0x7]
0x0000000140069CAB sub rax, 0x30 ;'0'
0x000000014002E028 mov qword ptr ss:[rsp+0x8], rax
0x000000014008BBCC mov rax, qword ptr ss:[rsp+0x8]
0x00000001400831F7 add rsp, 0x10
0x000000014002974F ret
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%=
0x0000000140014ACC mov rcx, qword ptr ss:[rsp+0xA8]
0x00000001400787FE mov qword ptr ss:[rsp+rcx*8+0xEC0], rax
0x00000001400AFE42 cmp qword ptr ss:[rsp+0xA8], 0x0
0x0000000140022C16 je 0x0000000140022C2F
0x00000001400CD021 mov rax, qword ptr ss:[rsp+0xA8]
0x00000001400EA72C mov rax, qword ptr ss:[rsp+rax*8+0xEC0]
0x00000001400ABE1C mov rcx, qword ptr ss:[rsp+0xA8]
0x00000001400E81E3 sub rcx, 0x1
0x00000001400906DB cmp rax, qword ptr ss:[rsp+rcx*8+0xEC0]
0x00000001400A9B93 jg 0x00000001400A9BAC
0x00000001400297BA mov rax, qword ptr ss:[rsp+0xA8]
0x00000001400BCBD3 add rax, 0x1
0x000000014007F965 mov qword ptr ss:[rsp+0xA8], rax
0x0000000140054381 cmp qword ptr ss:[rsp+0xA8], 0x2A
0x000000014001603F jge 0x0000000140016058
;初始化两个数组char ary[42],分别记录偶数位和奇数位每个字符是否出现
0x0000000140001A0A xor eax, eax
0x00000001400CCBF8 lea rcx, ss:[rsp+0xE90]
0x000000014004662E mov edx, eax
0x000000014004A3B8 mov r8d, 0x2A
0x000000014006EA24 mov qword ptr ss:[rsp+0x48], r8
0x0000000140098B05 mov dword ptr ss:[rsp+0x44], eax
;call memset
0x00000001400C9BCF jmp qword ptr ds:[0x0000000140004BD8]
0x00000001400930C5 lea rcx, ss:[rsp+0xE60]
0x00000001400EE6C6 mov edx, dword ptr ss:[rsp+0x44]
0x00000001400450F9 mov r8, qword ptr ss:[rsp+0x48]
;call memset
0x00000001400C9BCF jmp qword ptr ds:[0x0000000140004BD8]
;循环check
0x000000014007D9D5 mov qword ptr ss:[rsp+0xA0], 0x0 ;循环变量
0x0000000140002310 cmp qword ptr ss:[rsp+0xA0], 0x2A ;循环次数=2A
0x0000000140003980 jge 0x0000000140003999
;对0x2A一个求模一个整除, 等于是拿出了偶数位和奇数位数值
0x0000000140001F98 mov rax, qword ptr ss:[rsp+0xA0]
0x000000014002D5AC mov rax, qword ptr ss:[rsp+rax*8+0xEC0]
0x0000000140046C25 cqo
0x0000000140073E00 mov ecx, 0x2A
0x000000014009EA4F idiv rcx
0x000000014006EC35 mov qword ptr ss:[rsp+0x98], rdx
0x0000000140060863 mov rdx, qword ptr ss:[rsp+0xA0]
0x0000000140063300 mov rdx, qword ptr ss:[rsp+rdx*8+0xEC0]
0x0000000140017083 mov rax, rdx
0x00000001400C5CFF cqo
0x00000001400BCF6C idiv rcx
0x000000014008CCE3 mov qword ptr ss:[rsp+0x90], rax
0x00000001400BF3EF mov rax, qword ptr ss:[rsp+0x98]
;判断这个数值是否已经存在
0x000000014004B8F8 test byte ptr ss:[rsp+rax*1+0xE90], 0x1
0x00000001400ECE6A jne 0x00000001400ECE83
0x000000014005224C mov rax, qword ptr ss:[rsp+0x90]
0x0000000140015F89 test byte ptr ss:[rsp+rax*1+0xE60], 0x1
0x000000014006633F je 0x0000000140066358
;填入两个数组,记录当前已出现的数值
0x0000000140027ACE mov rax, qword ptr ss:[rsp+0x98]
0x00000001400E4C50 mov byte ptr ss:[rsp+rax*1+0xE90], 0x1
0x00000001400AC622 mov rax, qword ptr ss:[rsp+0x90]
0x00000001400B5248 mov byte ptr ss:[rsp+rax*1+0xE60], 0x1
0x0000000140037CD0 mov rax, qword ptr ss:[rsp+0xA0]
0x0000000140026ABB add rax, 0x1
0x00000001400258E6 mov qword ptr ss:[rsp+0xA0], rax
0x0000000140002310 cmp qword ptr ss:[rsp+0xA0], 0x2A
0x0000000140003980 jge 0x0000000140003999
;进入下一次循环
;初始化数组, size=1743
;@@@这里发现个问题, 后面给这个数组填数值的时候越界了
;@@@在这里纠结了很久, 照着代码抄下, 假装没看到数组访问越界就过了
0x000000014006B00F xor edx, edx
0x0000000140088714 lea rax, ss:[rsp+0xC0]
0x00000001400CA071 mov rcx, rax
0x0000000140062801 mov r8d, 0xD9E ;1743
call memset
0x00000001400C9BCF jmp qword ptr ds:[0x0000000140004BD8]
;嵌套的循环开始, 两两比较
;for (int i = 0; i < 42; i++)
0x00000001400C86F5 mov qword ptr ss:[rsp+0x88], 0x0
0x00000001400D320E cmp qword ptr ss:[rsp+0x88], 0x2A
0x0000000140056B2F jge 0x0000000140056B48
;for (int j = i+1; j < 42;j++)
0x00000001400CBE10 mov rax, qword ptr ss:[rsp+0x88]
0x0000000140052E9D add rax, 0x1
0x0000000140078F7F mov qword ptr ss:[rsp+0x80], rax
0x00000001400286DB cmp qword ptr ss:[rsp+0x80], 0x2A
0x000000014000D91A jge 0x000000014000D933
0x00000001400F755C mov rax, qword ptr ss:[rsp+0x88]
0x0000000140098656 mov rax, qword ptr ss:[rsp+rax*8+0xEC0]
0x0000000140001584 cqo
0x00000001400A4ADC mov ecx, 0x2A
0x000000014001F9E4 idiv rcx
0x000000014009D9EA mov r8, qword ptr ss:[rsp+0x80]
0x00000001400EDA1E mov r8, qword ptr ss:[rsp+r8*8+0xEC0]
0x000000014000EA19 mov rax, r8
0x00000001400A04C3 mov qword ptr ss:[rsp+0x38], rdx ;rsp_38 = ary[i]%42
0x0000000140037898 cqo
0x000000014008A550 idiv rcx
0x00000001400399F2 mov r8, qword ptr ss:[rsp+0x38] ;r8 = ary[j]%42
0x00000001400D4106 sub r8, rdx ;r8 = ary[j]%42- ary[i]%42
0x00000001400901F7 mov qword ptr ss:[rsp+0x78], r8
0x000000014009DAAD mov rdx, qword ptr ss:[rsp+0x88]
0x000000014000E4E3 mov rdx, qword ptr ss:[rsp+rdx*8+0xEC0]
0x00000001400EE409 mov rax, rdx
0x00000001400C5EE9 cqo
0x0000000140020832 idiv rcx
0x000000014008C074 mov r8, qword ptr ss:[rsp+0x80]
0x000000014006079F mov r8, qword ptr ss:[rsp+r8*8+0xEC0]
0x0000000140013395 mov qword ptr ss:[rsp+0x30], rax
0x00000001400C5CE1 mov rax, r8
0x000000014002FFF8 cqo
0x000000014007539E idiv rcx
0x000000014006BF8A mov rcx, qword ptr ss:[rsp+0x30]
0x00000001400DB4A6 sub rcx, rax ;rcx = ary[j]/42- ary[i]/42
0x00000001400E127D mov qword ptr ss:[rsp+0x70], rcx
;if(ary[j]%42- ary[i]%42 > 0)
0x0000000140073B88 cmp qword ptr ss:[rsp+0x78], 0x0
0x000000014006437E jge 0x0000000140064397
; 负数 则 取反
0x00000001400BFF7E xor eax, eax
0x00000001400EACB4 mov ecx, eax
0x0000000140080A4A mov rdx, rcx ;
0x00000001400A7967 sub rdx, qword ptr ss:[rsp+0x78]
0x00000001400517AC mov qword ptr ss:[rsp+0x78], rdx
0x000000014000B3C6 sub rcx, qword ptr ss:[rsp+0x70]
0x000000014008DA3A mov qword ptr ss:[rsp+0x70], rcx
0x0000000140064397:
;ary[j]/42 -ary[i]/42 +0x29
0x00000001400B368C mov rax, qword ptr ss:[rsp+0x70]
0x0000000140079E70 add rax, 0x29
0x00000001400DE855 mov qword ptr ss:[rsp+0x70], rax
;这里看出是个二维数组访问
;说明上面初始化的数组定义为char ary[?][42]
0x000000014007C0C8 imul rax, qword ptr ss:[rsp+0x70], 0x2A
0x00000001400DC9B8 lea rcx, ss:[rsp+0xC0]
0x0000000140038FE8 add rcx, rax
0x0000000140067202 mov rax, qword ptr ss:[rsp+0x78]
; 判断不为1
0x000000014008B8FD test byte ptr ds:[rcx+rax*1], 0x1
0x0000000140063B11 je 0x0000000140063B2A
; 填1
0x00000001400F9BFC imul rax, qword ptr ss:[rsp+0x70], 0x2A
0x000000014007F148 lea rcx, ss:[rsp+0xC0]
0x00000001400EB582 add rcx, rax
0x0000000140065E6F mov rax, qword ptr ss:[rsp+0x78]
0x00000001400F535F mov byte ptr ds:[rcx+rax*1], 0x1
; j++
0x0000000140013FC1 mov rax, qword ptr ss:[rsp+0x80]
0x0000000140073E8D add rax, 0x1
0x00000001400B9738 mov qword ptr ss:[rsp+0x80], rax
0x00000001400286DB cmp qword ptr ss:[rsp+0x80], 0x2A
0x000000014000D91A jge 0x000000014000D933
;进入下一次循环
;strncmp
0x0000000140039540 lea rcx, ss:[rsp+0x1010]
0x00000001400CE591 lea rdx, ds:[0x0000000140004521]
0x000000014004CACF mov r8d, 0x1C
0x000000014004FED9 call qword ptr ds:[0x0000000140004C98]
0x03 回溯法穷举flag
int n = 0;
#define BORDER 42
char board[BORDER] = { 0 };
char tb[200][42] = { 0 };
char x[2000] = { 0 };
char y[2000] = { 0 };
bool check(char row, char col)
{
for (char i = 0; i < row; i++)
{
if (board[i] == col)
{
return false;
}
}
short sum = 0;
for (char i = 0; i < row; i++)
{
for (char j = i+1; j < row; j++)
{
int tmp1 = j - i;
int tmp2 = board[j] - board[i];
if (tmp2 < 0)
{
tmp1 = 0 - tmp1;
tmp2 = 0 - tmp2;
}
tmp1 = tmp1 + 0x29;
x[sum] = tmp1;
y[sum] = tmp2;
sum++;
}
}
memset(tb, 0, sizeof(tb));
for (short j = 0; j < sum; j++)
{
tb[x[j]][y[j]] = 1;
}
for (char i = 0; i < row; i++)
{
//(i, board[i])
//(row, col)
int tmp1 = row - i;
int tmp2 = col - board[i];
if (tmp2 < 0)
{
tmp1 = 0 - tmp1;
tmp2 = 0 - tmp2;
}
tmp1 = tmp1 + 0x29;
if (tb[tmp1][tmp2] == 1)
{
return false;
}
}
return true;
}
void fxck(char row)
{
if (row == BORDER)
{
//output
n++;
printf("%d: 02152S3X4Z5Q6C7T819/ADB%cC*DL", n, '%');
for (int i = 14; i < BORDER; i++)
{
printf("%c%c", getccc(i), getccc(board[i]));
}
printf("\r\n");
return;
}
for (char col = 0; col < BORDER; col++)
{
if (check(row, col))
{
board[row] = col;
fxck(row + 1);
}
}
}
int main(int argc, const char** argv, const char** envp)
{
//"02152S3X4Z5Q6C7T819/ADB%C*DL"
LPCSTR yz = "25SXZQCT1/D%*L";
for(int i = 0; i< 14;i++)
{
auto idx= getidx(yz[i]);
board[i] = idx;
}
fxck(14);
printf("n = %d \r\n", n);
return 0;
}
Microsoft Windows [版本 10.0.19042.985]
(c) Microsoft Corporation。保留所有权利。
C:\Users\KuCha\Desktop\crack_login\x64\Release>crack_login.exe
1: 02152S3X4Z5Q6C7T819/ADB%C*DLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8*F/-%V=A
n = 1
C:\Users\KuCha\Desktop\crack_login\x64\Release>
02152S3X4Z5Q6C7T819/ADB%CDLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8F/-%V=A
0x04 总结
往期解析
1. 看雪·深信服 2021 KCTF 春季赛 | 第二题设计思路及解析
球分享
球点赞
球在看