安恒周周练-西湖论剑特别版
本帖最后由 yechen123 于 2019-3-28 17:14 编辑题目虽然简单 但是蛮有意思的
Mysterious
从DialogBoxParamA 函数中定位处理函数
int __stdcall sub_401090(HWND hWnd, int a2, int a3, int a4)
{
char v5; //
CHAR Text; //
char v7; //
__int16 v8; //
char v9; //
int v10; //
CHAR String; //
char v12; //
char v13; //
char v14; //
memset(&String, 0, 0x104u);
v10 = 0;
if ( a2 == 16 )
{
DestroyWindow(hWnd);
PostQuitMessage(0);
}
else if ( a2 == 273 )
{
if ( a3 == 1000 )
{
GetDlgItemTextA(hWnd, 1002, &String, 260);
strlen(&String);
if ( strlen(&String) > 6 )
ExitProcess(0);
v10 = atoi(&String) + 1;
if ( v10 == 123 && v12 == 120 && v14 == 122 && v13 == 121 )
{
strcpy(Text, "flag");
memset(&v7, 0, 0xFCu);
v8 = 0;
v9 = 0;
_itoa(v10, &v5, 10);
strcat(Text, "{");
strcat(Text, &v5);
strcat(Text, "_");
strcat(Text, "Buff3r_0v3rf|0w");
strcat(Text, "}");
MessageBoxA(0, Text, "well done", 0);
}
SetTimer(hWnd, 1u, 0x3E8u, TimerFunc);
}
if ( a3 == 1001 )
KillTimer(hWnd, 1u);
}
return 0;
}
输入的字符不能超过6位要为6位
if ( v10 == 123 && String == 120 && String == 122 && String == 121 )
可以得知 经过atoi函数转为数字后 +1 要等于123后边三位是xyz
所以key是122xyz
findKey
打开软件后发现没有输入窗口
查看函数
ATOM __cdecl sub_4011D0(HINSTANCE hInstance)
{
WNDCLASSEXA v2; //
v2.cbSize = 48;
v2.style = 3;
v2.lpfnWndProc = (WNDPROC)sub_401014;
v2.cbClsExtra = 0;
v2.cbWndExtra = 0;
v2.hInstance = hInstance;
v2.hIcon = LoadIconA(hInstance, (LPCSTR)0x6B);
v2.hCursor = LoadCursorA(0, (LPCSTR)0x7F00);
v2.hbrBackground = (HBRUSH)6;
v2.lpszMenuName = (LPCSTR)109;
v2.lpszClassName = ClassName;
v2.hIconSm = LoadIconA(hInstance, (LPCSTR)0x6C);
return RegisterClassExA(&v2);
}
发现处理函数sub_401014
在函数中发现调用了 DialogBoxParamA
.text:00401721 loc_401721: ; CODE XREF: .text:00401714↑j
.text:00401721 mov esi, esp
.text:00401723 push 0
.text:00401725 push offset sub_40100A
.text:0040172A mov eax,
.text:0040172D push eax
.text:0040172E push 67h
.text:00401730 mov ecx, hInstance
.text:00401736 push ecx
.text:00401737 call ds:DialogBoxParamA
.text:0040173D cmp esi, esp
处理函数是sub_40100A
int __stdcall sub_401B20(HWND hDlg, int a2, int a3, int a4)
{
switch ( a2 )
{
case 272:
return 1;
case 273:
if ( (unsigned __int16)a3 != 1 && (unsigned __int16)a3 != 2 )
goto LABEL_6;
EndDialog(hDlg, (unsigned __int16)a3);
return 1;
case 514:
LABEL_6:
byte_428C54 = 49;
return 0;
case 517:
byte_428C54 = 51;
break;
case 520:
if ( dword_428D58 < 3 )
++dword_428D5C;
byte_428C54 = 50;
break;
default:
return 0;
}
return 0;
}
可以看到是通过特定的消息让缓冲区赋值 1 2 3
再看
.text:004018CB loc_4018CB: ; CODE XREF: .text:004018B8↑j
.text:004018CB push offset byte_428C54 ; 1
.text:004018D0 call _strlen
.text:004018D5 add esp, 4
.text:004018D8 test eax, eax
.text:004018DA jbe loc_401A80
.text:004018E0 push 100h
.text:004018E5 push 0
.text:004018E7 lea edx,
.text:004018ED push edx
.text:004018EE call _memset ; 初始化
.text:004018F3 add esp, 0Ch ; 0x100
.text:004018F6 push offset byte_428C54
.text:004018FB call _strlen
.text:00401900 add esp, 4
.text:00401903 push eax
.text:00401904 push offset byte_428C54
.text:00401909 lea eax,
.text:0040190F push eax
.text:00401910 call _memcpy
.text:00401915 add esp, 0Ch
.text:00401918 push offset byte_428C54
.text:0040191D
.text:0040191D loc_40191D: ; CODE XREF: .text:0040193D↓j
.text:0040191D push offset byte_428C54
.text:00401922 call _strlen
.text:00401927 add esp, 4
.text:0040192A push eax
.text:0040192B push offset byte_428C54
.text:00401930 call j_md5_en ; 加密后再放到c54
.text:00401935 add esp, 0Ch
.text:00401938 nop
.text:00401939 jz short loc_401948
.text:0040193B jnz short loc_401948
.text:0040193D jmp short near ptr loc_40191D+2
.text:0040193F ; ---------------------------------------------------------------------------
.text:0040193F push eax
.text:00401940 mov eax, ds:MessageBoxA
.text:00401945 call eax ; MessageBoxA
.text:00401947 pop eax
.text:00401948
.text:00401948 loc_401948: ; CODE XREF: .text:00401939↑j
.text:00401948 ; .text:0040193B↑j
.text:00401948 nop
.text:00401949 mov ecx, 8
.text:0040194E mov esi, offset a0kkD1a55k222k2 ; "0kk`d1a`55k222k2a776jbfgd`06cjjb"
.text:00401953 lea edi, ;
.text:00401959 rep movsd
.text:0040195B movsb
.text:0040195C mov ecx, 37h ; 55
.text:00401961 xor eax, eax
.text:00401963 lea edi, ; 2cb清0
.text:00401969 rep stosd
.text:0040196B stosw
.text:0040196D stosb
.text:0040196E mov cx, ds:word_423048 ; 0x5353
.text:00401975 mov , cx
.text:0040197C mov dl, ds:byte_42304A ; 0
.text:00401982 mov , dl
.text:00401988 xor eax, eax
.text:0040198A mov , eax ; 0
.text:00401990 mov , ax
.text:00401997 mov , al
.text:0040199D lea ecx,
.text:004019A3 push ecx
.text:004019A4 call _strlen
.text:004019A9 add esp, 4
.text:004019AC push eax ; len
.text:004019AD lea edx,
.text:004019B3 push edx
.text:004019B4 lea eax,
.text:004019BA push eax
.text:004019BB call sub_401005 ; 异或
.text:004019C0 add esp, 0Ch
.text:004019C3 lea ecx,
.text:004019C9 push ecx
.text:004019CA push offset byte_428C54
.text:004019CF call __strcmpi
.text:004019D4 add esp, 8
.text:004019D7 test eax, eax
.text:004019D9 jnz short loc_401A37
.text:004019DB push 32h
.text:004019DD push offset unk_423030
.text:004019E2 lea edx,
.text:004019E8 push edx
.text:004019E9 call _memcpy
.text:004019EE add esp, 0Ch
.text:004019F1 lea eax,
.text:004019F7 push eax
.text:004019F8 call _strlen
.text:004019FD add esp, 4
.text:00401A00 push eax
.text:00401A01 lea ecx,
.text:00401A07 push ecx
.text:00401A08 lea edx,
.text:00401A0E push edx
.text:00401A0F call sub_401005 ; 异或
.text:00401A14 add esp, 0Ch
.text:00401A17 mov esi, esp
.text:00401A19 push 32h
.text:00401A1B push 0
.text:00401A1D lea eax,
.text:00401A23 push eax
.text:00401A24 mov ecx,
.text:00401A27 push ecx
.text:00401A28 call ds:MessageBoxA
.text:00401A2E cmp esi, esp
.text:00401A30 call __chkesp
.text:00401A35 jmp short loc_401A80
发现会调用缓冲区的数据 判断是不是6位
在传入一个函数
int __cdecl md5_en(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
int result; // eax
DWORD i; //
CHAR String2; //
BYTE v6; //
DWORD pdwDataLen; //
HCRYPTHASH phHash; //
HCRYPTPROV phProv; //
if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
return 0;
if ( CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash) )
{
if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
{
CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
*lpString1 = 0;
for ( i = 0; i < pdwDataLen; ++i )
{
wsprintfA(&String2, "%02X", v6);
lstrcatA(lpString1, &String2);
}
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
result = 1;
}
else
{
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
result = 0;
}
}
else
{
CryptReleaseContext(phProv, 0);
result = 0;
}
return result;
}
查文档 发现它应该是windows提供的一个加密库
看CryptCreateHash 的参数应该是MD5加密
后边的代码
.text:00401949 mov ecx, 8
.text:0040194E mov esi, offset a0kkD1a55k222k2 ; "0kk`d1a`55k222k2a776jbfgd`06cjjb"
.text:00401953 lea edi,
.text:00401959 rep movsd
.text:0040195B movsb
.text:0040195C mov ecx, 37h ; 55
.text:00401961 xor eax, eax
.text:00401963 lea edi, ; 2cb清0
.text:00401969 rep stosd
.text:0040196B stosw
.text:0040196D stosb
.text:0040196E mov cx, ds:word_423048 ; 0x5353
.text:00401975 mov , cx
.text:0040197C mov dl, ds:byte_42304A ; 0
.text:00401982 mov , dl
.text:00401988 xor eax, eax
.text:0040198A mov , eax ; 0
.text:00401990 mov , ax
.text:00401997 mov , al
.text:0040199D lea ecx,
.text:004019A3 push ecx
.text:004019A4 call _strlen
.text:004019A9 add esp, 4
.text:004019AC push eax ; len
.text:004019AD lea edx,
.text:004019B3 push edx
.text:004019B4 lea eax,
.text:004019BA push eax
.text:004019BB call sub_401005 ; 异或
程序中的一串字符会传入sub_401005 这个函数 和字符"SS"异或
得到一串md5c8837b23ff8aaa8a2dde915473ce0991
解密之后是123321
此时 可以下断点修改程序逻辑 让程序运行到上边的函数然后byte_428C54这个缓冲区里边的数据改成123321就可以弹出flag了
本来以为是错误的没想到提交对了。。
CrackRTF
int main_0()
{
DWORD password_len; // eax
DWORD v1; // eax
CHAR String; //
int v4; //
CHAR String1; //
BYTE password; //
memset(&password, 0, 0x104u);
memset(&String1, 0, 0x104u);
v4 = 0;
printf("pls input the first passwd(1): ");
scanf("%s", &password);
if ( strlen((const char *)&password) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v4 = atoi((const char *)&password);
if ( v4 < 100000 ) // 大于100000
ExitProcess(0);
strcat((char *)&password, "@DBApp");
password_len = strlen((const char *)&password);
sub_40100A(&password, password_len, &String1);
if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )// shal加密
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(&String, 0, 0x104u);
scanf("%s", &String);
if ( strlen(&String) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
strcat(&String, (const char *)&password);
memset(&String1, 0, 0x104u);
v1 = strlen(&String);
sub_401019((BYTE *)&String, v1, &String1);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )// md5加密
{
if ( !sub_40100F(&String) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}
先输入第一个密码 必须是6数字 并且要大于100000
在后边加字符串"@DBApp"后再传入 sub_40100A 加密
int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
int result; // eax
DWORD i; //
CHAR String2; //
char v6; //
DWORD pdwDataLen; //
HCRYPTHASH phHash; //
HCRYPTPROV phProv; //
if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
return 0;
if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )
{
if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
{
CryptGetHashParam(phHash, 2u, (BYTE *)v6, &pdwDataLen, 0);
*lpString1 = 0;
for ( i = 0; i < pdwDataLen; ++i )
{
wsprintfA(&String2, "%02X", (unsigned __int8)v6);
lstrcatA(lpString1, &String2);
}
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
result = 1;
}
else
{
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
result = 0;
}
}
else
{
CryptReleaseContext(phProv, 0);
result = 0;
}
return result;
}
应该是shal加密
直接写脚本爆破
import hashlib
flag2 = "@DBApp"
for i in range(100000,999999):
h2 = hashlib.sha1(str(i)+flag2)
flags = h2.hexdigest()
if "6e32d0943418c2c" in flags:
print (str(i)+flag2)
print flags
得到123321@DBApp
然后在输入第二个密码但是没有限制这个密码的范围
在第二个密码后边加上123321@DBApp后经过md5加密
传入sub_40100F 函数 6位不确定范围字符爆破太久
可以看看 sub_40100F这个函数
char __cdecl sub_4014D0(LPCSTR lpString)
{
LPCVOID lpBuffer; //
DWORD NumberOfBytesWritten; //
DWORD nNumberOfBytesToWrite; //
HGLOBAL hResData; //
HRSRC hResInfo; //
HANDLE hFile; //
hFile = 0;
hResData = 0;
nNumberOfBytesToWrite = 0;
NumberOfBytesWritten = 0;
hResInfo = FindResourceA(0, (LPCSTR)0x65, "AAA");
if ( !hResInfo )
return 0;
nNumberOfBytesToWrite = SizeofResource(0, hResInfo);
hResData = LoadResource(0, hResInfo);
if ( !hResData )
return 0;
lpBuffer = LockResource(hResData);
sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);
hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);
if ( hFile == (HANDLE)-1 )
return 0;
if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
return 0;
CloseHandle(hFile);
return 1;
}
里边查找名为“AAA”的资源
取出数值 并跟 输入的密码2+输入的密码1+“@DBApp” 异或
并生成.rtf文件最终的flag应该就在.rtf文件里边
用ResourceHacer 软件查看资源
取出里边的数据 虽然猜一个6位的密码2异或试试
i = [0x05,0x7D,0x41,0x15,0x26,0x01,0x6D,0x53,0x5D,0x40,0x5B,0x6D,0x21,0x2A,0x31,0x28,0x13,0x00,0x19,0x18,0x00,0x57,0x1C,0x54,0x54,0x54,0x55,0x03,0x6E,0x55,0x25,0x22,
0x2E,0x20,0x1E,0x17,0x4F,0x11,0x00,0x52,0x1C,0x54,0x54,0x54,0x5F,0x52,0x5C,0x56,0x26,0x21,0x70,0x71,0x45,0x42,0x05,0x7D,0x55,0x0E,0x2E,0x44,0x45,0x50,0x5F,0x48,
0x6E,0x57,0x70,0x18,0x24,0x2C,0x1F,0x14,0x1B,0x53,0x5D,0x3D,0x26,0x40,0x43,0x43,0x05,0x6F,0x54,0x52,0x28,0x25,0x30,0x32,0x15,0x04,0x4F,0x12,0x07,0x41,0x1C,0x17,
0x52,0x50,0x6F,0x14,0x51,0x54,0x1C,0x63,0x21,0x22,0x2C,0x57,0x1B,0x14,0x08,0x1C,0x3D,0x3D,0x3B,0x49,0x6F,0x19,0x6E,0x56,0x25,0x2A,0x27,0x33,0x11,0x04,0x11,0x53,
0x13,0x2C,0x33,0x56,0x45,0x57,0x57,0x5A,0x46,0x11,0x75,0x6A,0x76,0x70,0x5E,0x41,0x4B,0x0F,0x02,0x54,0x71,0x05,0x0A,0x4F,0x6F,0x45,0x5B,0x54,0x37,0x2F,0x2B,0x2F,
0x14,0x44,0x22,0x54,0x50,0x50,0x1C,0x40,0x50,0x40,0x57,0x6F,0x5E,0x50,0x2E,0x23,0x70,0x71,0x45,0x42,0x22,0x47,0x03,0x3D,0x26,0x43,0x03,0x02,0x13,0x75,0x5E,0x50,
0x27,0x18,0x39,0x0F,0x40,0x2F,0x33,0x11,0x41,0x04,0x1F,0x76,0x43,0x57,0x56,0x6C,0x70,0x44,0x27,0x37,0x1E,0x3C,0x2C,0x00,0x1F,0x53,0x3E,0x6B,0x3D,0x3D,0x3B,0x32]
flag = "123321123321@DBApp"
cout = len(flag)
for q in range(len(i)):
i ^= ord(flag)
flags= ""
for q in i:
flags += chr(q)
print i
print flags
有flag了 但是不完整
此时 可以从本地中搜索.rtf的文件 查看格式
前面6位的格式应该是{\rtf1
逆推的到密码2~!3a@0
再异或
i = [0x05,0x7D,0x41,0x15,0x26,0x01,0x6D,0x53,0x5D,0x40,0x5B,0x6D,0x21,0x2A,0x31,0x28,0x13,0x00,0x19,0x18,0x00,0x57,0x1C,0x54,0x54,0x54,0x55,0x03,0x6E,0x55,0x25,0x22,
0x2E,0x20,0x1E,0x17,0x4F,0x11,0x00,0x52,0x1C,0x54,0x54,0x54,0x5F,0x52,0x5C,0x56,0x26,0x21,0x70,0x71,0x45,0x42,0x05,0x7D,0x55,0x0E,0x2E,0x44,0x45,0x50,0x5F,0x48,
0x6E,0x57,0x70,0x18,0x24,0x2C,0x1F,0x14,0x1B,0x53,0x5D,0x3D,0x26,0x40,0x43,0x43,0x05,0x6F,0x54,0x52,0x28,0x25,0x30,0x32,0x15,0x04,0x4F,0x12,0x07,0x41,0x1C,0x17,
0x52,0x50,0x6F,0x14,0x51,0x54,0x1C,0x63,0x21,0x22,0x2C,0x57,0x1B,0x14,0x08,0x1C,0x3D,0x3D,0x3B,0x49,0x6F,0x19,0x6E,0x56,0x25,0x2A,0x27,0x33,0x11,0x04,0x11,0x53,
0x13,0x2C,0x33,0x56,0x45,0x57,0x57,0x5A,0x46,0x11,0x75,0x6A,0x76,0x70,0x5E,0x41,0x4B,0x0F,0x02,0x54,0x71,0x05,0x0A,0x4F,0x6F,0x45,0x5B,0x54,0x37,0x2F,0x2B,0x2F,
0x14,0x44,0x22,0x54,0x50,0x50,0x1C,0x40,0x50,0x40,0x57,0x6F,0x5E,0x50,0x2E,0x23,0x70,0x71,0x45,0x42,0x22,0x47,0x03,0x3D,0x26,0x43,0x03,0x02,0x13,0x75,0x5E,0x50,
0x27,0x18,0x39,0x0F,0x40,0x2F,0x33,0x11,0x41,0x04,0x1F,0x76,0x43,0x57,0x56,0x6C,0x70,0x44,0x27,0x37,0x1E,0x3C,0x2C,0x00,0x1F,0x53,0x3E,0x6B,0x3D,0x3D,0x3B,0x32]
flag = "~!3a@0123321@DBApp"
cout = len(flag)
for q in range(len(i)):
i ^= ord(flag)
flags= ""
for q in i:
flags += chr(q)
print i
print flags
得到flag
qdam 发表于 2019-4-3 16:07
请问如何快速判断一个加密函数是常用的加密方式呢,例如md5,sha
作者自己写的加密源码就看特征值或者加密方式。帖子中的题目调用加密库的话就看参数的值,不同的参数代表不同的加密。 qdam 发表于 2019-4-1 22:32
请问为什么要从DialogBoxParamA 函数中定位处理函数,是就这个程序单独而言还是说所有带有消息窗口程序都是 ...
针对DialogBoxParamA这个api,可以看看这个api的定义 提前点赞666 感谢分享,支持一下。 谢谢分享 学习学习 tql 谢谢分享 感谢分享0
来学习一下 打卡,滴滴 学习了、谢谢楼主发帖分享 谢谢LZ分享。