2024春节解题领红包之Windows 高级题
解题领红包之Windows 高级题# 分析:
# crackme2024.exe
x64位程序upx 脱壳,x64dbg设置异常,手动脱壳,略
## 反调试
cinit-->initterm_4 定位到如下函数
### VEH_antiBP_140001670
```c
__int64 VEH_antiBP_140001670()
{
qword_140020E58 = findCC_1400022F0(0x64, 0i64);
AddVectoredExceptionHandler(1u, (PVECTORED_EXCEPTION_HANDLER)Handle);
memset(qword_140020EA0, 0, 0x4D0ui64);
qword_140021370 = check_peb_atdbg_140002350();
RemoveVectoredExceptionHandler(Handle);
return 0i64;
}
```
### mapview_and_antidbg_140001000
```c
__int64 mapview_and_antidbg_140001000()
{
mapview_and_antidbg_1400012F0();
return onexit_140002510(sub_1400136D0);
}
__int64 *mapview_and_antidbg_1400012F0()
{
//
qword_140020E98 = sub_140002340() & 0xFFFFFFFFFFFFF000ui64;
getMapView_140001700();
if ( !mapAddr_140020E90 )//共享内存,与crackme2024service.exe共享
return &qword_1400213A0;
v0 = sub_140001A90;
isCC_140020E40 = findCC_1400022F0(0x14, 0i64);
ModuleHandleW = GetModuleHandleW(ModuleName);
CsrGetProcessId = GetProcAddress(ModuleHandleW, ProcName);
if ( CsrGetProcessId )
{
// 反调试,
v3 = CsrGetProcessId();
v4 = OpenProcess(0x400u, 0, v3);
if ( v4 )
{
CloseHandle(v4);
v0 = sub_140001AB0;
}
}
*(_QWORD *)mapAddr_140020E90 = v0;
return &qword_1400213A0;
}
```
### antidbg_checkthread_140001020
```c
_onexit_t antidbg_checkthread_140001020()
{
*(_QWORD *)&ThreadId = 0i64;
qword_1400213B0 = 0i64;
qword_1400213B0 = (__int64)CreateThread(0i64, 0i64, (LPTHREAD_START_ROUTINE)StartAddress, obf_140001AC0, 0, &ThreadId);
return onexit_140002510(nullsub_2);
}
__int64 __fastcall StartAddress(LPVOID lpThreadParameter)
{
DWORD ThreadId; // BYREF
HANDLE Handles; // BYREF
InitializeCriticalSection(&CriticalSection);
Handles = CreateThread(0i64, 0i64, (LPTHREAD_START_ROUTINE)anti1_140001470, obf_140001AC0, 0, &ThreadId);//检测到软件断点后干扰后续共享内存的操作
Sleep(1110u);
Handles = CreateThread(0i64, 0i64, (LPTHREAD_START_ROUTINE)anti_debug_1400014E0, obf_140001AC0, 0, &ThreadId);//作用同上,利用主动触发VEH处理函数进行检测,
WaitForMultipleObjects(2u, Handles, 1, 0xFFFFFFFF);
DeleteCriticalSection(&CriticalSection);
return 0i64;
}
```
## 客户端逻辑
### main
```c
__int64 __fastcall main_140001AD0(int a1, __int64 a2)
{
//
printf_s("%s @ www.52pojie.cn\n", &ConsoleTitle);
onexit((_onexit_t)sub_140001E40); // printf ==>"\nThank you, HAPPY NEW YEAR!!!!!\n"
SetConsoleTitleA(&ConsoleTitle);
printf("Happy New Year!\nAuthor: solly\n\n");
v9 = 0;
memset(serial, 0, 0x104ui64);
StdHandle = GetStdHandle(0xFFFFFFF5);
if ( a1 <= 3 )
{
printf(" Enter your uid: ");
msvcrt_scanf("%lu", &v9);
uid = v9;
if ( v9 )
{
printf("Enter your serial: ");
msvcrt_scanf("%s", serial);
uid = v9;
}
}
else
{
v9 = strtoui64(*(const char **)(a2 + 8), (char **)v8, 0xA);
memcpy_s(serial, 36ui64, *(const void *const *)(a2 + 0x10), 0x104ui64);
uid = v9;
}
if ( !uid )
goto LABEL_12;
v6 = 0xFFFFFFFFFFFFFFFFui64;
do
++v6;
while ( serial );
if ( v6 >= 35 )
{
if ( (unsigned __int8)Checking_140001CF0(uid, serial) )
{
printf("\nChecking result: ");
SetConsoleTextAttribute(StdHandle, 9u);
printf("SUCCESS. ");
SetConsoleTextAttribute(StdHandle, 7u);
printf("Congratulations!!\n\n");
printf("You can run crackme2024service.exe /UnregServer as administrator to unload the server.\n");
}
else
{
printf("\nChecking result: ");
SetConsoleTextAttribute(StdHandle, 0xCu);
printf("FAILURE. ");
SetConsoleTextAttribute(StdHandle, 7u);
printf("Try it again!!!!!\n\n");
}
}
else
{
LABEL_12:
printf("\nERROR: uid or serial is error\n");
}
return 0i64;
}
```
### Checking_140001CF0
```c
__int64 __fastcall Checking_140001CF0(unsigned int uid, const char *a2)
{
//
v6 = 0;
ret_cc_140020E50 = findCC_1400022F0(0x15A, 0x38i64);
if ( CoInitialize(0i64) >= 0 )
{
if ( CoCreateInstance(&rclsid, 0i64, 0x14u, &riid, (LPVOID *)&ppv.lpVtbl) < 0 )
{
printf("\nCreate Server Instance failure. Please run crackme2024service.exe /RegServer as administrator first.\n");
}
else
{
memset(serial, 0, 0xC8ui64);
strcpy_s(serial, 0xC8ui64, a2);
//void setUID(uint id);
(*((void (__fastcall **)(IUnknownVtbl *, _QWORD))ppv.lpVtbl->QueryInterface + 7))(ppv.lpVtbl, uid);
if ( *(_QWORD *)mapAddr_140020E90 )
//uid计算,调用sub_140001A90// return (a1 * a1 * a1) ^ 0x323032796C6C6F73i64;
*(_QWORD *)mapAddr_140020E90 = (*(__int64 (__fastcall **)(_QWORD))mapAddr_140020E90)(*((unsigned int *)mapAddr_140020E90
+ 2));
// void setSerial(Byte[] serial);
(*((void (__fastcall **)(IUnknownVtbl *, char *))ppv.lpVtbl->QueryInterface + 8))(ppv.lpVtbl, serial);
// sbyte checkSerial();
if ( (*((unsigned int (__fastcall **)(IUnknownVtbl *, char *))ppv.lpVtbl->QueryInterface + 9))(ppv.lpVtbl, v6) == 1 )
{
v6 = 0;
printf("Running failure. Please run crackme2024service.exe /RegServer as administrator first.\n");
}
// :IUnknown_Release_Proxy
(*((void (__fastcall **)(IUnknownVtbl *))ppv.lpVtbl->QueryInterface + 2))(ppv.lpVtbl);
}
}
CoUninitialize();
return (unsigned __int8)v6;
}
```
# crackme2024service.exe
## ATL COM服务端
保护器: Themida/Winlicense(3.XX)
(https://github.com/ergrelet/unlicense)
脱壳,x32dbg 修改进程名,配置ScyllaHide Plugin反反调试
对ATL COM了解不多,正向写个程序熟悉了一下
(https://blog.csdn.net/pathfinder1987/article/details/86093149)
主要对COM接口进行分析
利用OleView对IATLCrackmeObject接口进行查看
ida 中对ATL::CComObject<class CATLCrackmeObject>进行分析
### setUID_401280
uid 存储到共享内存+8偏移处,DWORD
```c
int __stdcall setUID_401280(CATLCrackmeObject *a1, int uid)
{
int result; // eax
// *(int*)&a1->MapViewOfFile=uid;
*(_DWORD *)&a1->MapViewOfFile_C = uid;
result = 0;
a1->numb = 0i64;
return result;
}
```
### setSerial_4012B0
序列号长度35,分成4块,中间使用‘-’连接
序列号16进制字符串各部分分别转换成ulong保存
```C
int __stdcall setSerial_4012B0(CATLCrackmeObject *a1, char *serial)
{
//
v2 = serial;
serial_array_10 = a1->serial_array_10;
memset(a1->serial_array_10, 0, sizeof(a1->serial_array_10));
v4 = 0;
// 4*8+3=35
// 11111111-22222222-33333333-44444444
for ( i = strstr(serial, SubStr); i; i = strstr(i + 1, SubStr) )
{
*i = 0;
// 16进制字符串转ulong
v6 = strtoul(v2, &EndPtr, 16);
v2 = i + 1;
*serial_array_10 = v6;
++v4;
++serial_array_10;
}
a1->serial_array_10 = strtoul(v2, &EndPtr, 0x10);
// 取前8字节
a1->numb = *(_QWORD *)a1->MapViewOfFile_C;
return 0;
}
```
### checkSerial_401360
变换逻辑,对应写成逆过程;
```c
int __stdcall checkSerial_401360(CATLCrackmeObject *a1, bool *isEqual)
{
//
numb = a1->numb;
if ( a1 == (CATLCrackmeObject *)-24 )
{
*_errno() = 22;
_invalid_parameter_noinfo();
serial = 0i64;
}
else
{
// 取16字节,即4个int值,serial共有4部分
serial = *(_OWORD *)a1->serial_array_10;
}
v16 = 0;
*(_OWORD *)serials_data = 0i64;
zero = NtCurrentPeb()->BeingDebugged;
*(_OWORD *)serials_data = serial;
result = serials_data;
v4 = 2;
do
{
serial_part = *result;
tb2 = &table2_41F8D0;
serial_next = result;
do
{
t2 = *tb2;
tb2 += -1u;
serial_part2 = serial_part ^ (zero + t2);
serial_part = serial_next ^ (table3_41E8D0
+ (table3_41E8D0 ^ (table3_41E8D0[(unsigned __int8)serial_part2]
+ table3_41E8D0)));
serial_next = serial_part2;
}
while ( (int)tb2 >= (int)&table2_41F8D0 );
part = serial_part ^ table2_41F8D0;
part2_ = serial_part2 ^ table2_41F8D0;
result = part;
*result = part2_;
result += 2;
--v4;
}
while ( v4 );
LOBYTE(v16) = 0;
// 8字节
*isEqual = numb == _strtoui64((const char *)serials_data, 0, 16);
return 0;
}
```
py
```python
def check_serial(serials_data, table2, table3):
result=*4
for i in range(0,4,2):
serial_part = serials_data
# tb2 = table2[::-1]
serial_next = serials_data
for j in range(17,1,-1):
t2 = table2
tb_index = serial_part ^ t2
xordata=(table3[(tb_index >> 24) & 0xFF] + (table3[(tb_index >> 16) & 0xFF] ^
(table3[(tb_index >> 0) & 0xFF] +
table3[(tb_index >> 8) & 0xFF])))&0xffffffff
serial_part = serial_next ^ xordata
serial_next = tb_index
result = serial_part^table2
result = serial_next^table2
bs=b''
for x in result:
bs+=x.to_bytes(4,'little')
# print(x.to_bytes(4,'little'))
print('serial_tf:\n',bs,bs.hex())
# print(serials_data.hex())
return result
```
# 注册脚本
table2_41F8D0、table3_41E8D0需动态dump
```python
table2_41F8D0 = [
0x5226ADD8, 0x5E55C820, 0xA30A9E51, 0x22BB06C2, 0x5A261794, 0x0C719373, 0x47B81378, 0xFE536644,
0x4659CBBC, 0xEBA4557D, 0x60D52F41, 0x3D6BB2C4, 0x9D15F01B, 0x160D9EB4, 0xECCA07BF, 0x36D0CF94,
0xAE389637, 0xF868B19B
]# 填入已知的 table2 数据
from tabledata import table3
table3_41E8D0 = []
for i in range(0,4):
table3_41E8D0.append(table3)
def numbTotarget(numb:int):
traget=*4
numbstr='%0x'%numb
bs=numbstr.encode()#numb.to_bytes(8,'little')
traget =[ int.from_bytes(bs,'little') for i in range(4)]
return traget
def reverse_check_serial(result, table2, table3):
# Initialize a list to store the reversed serials_data
reversed_serials_data =
for i in range(2,-1,-2):
serial_part = result^table2
serial_next = result^table2
for j in range(2,18):
tb_index=serial_next
xordata=(table3[(tb_index >> 24) & 0xFF] + (table3[(tb_index >> 16) & 0xFF] ^
(table3[(tb_index >> 0) & 0xFF] +
table3[(tb_index >> 8) & 0xFF])))&0xffffffff
serial_next=serial_part^ xordata
serial_part=tb_index^table2
#re begain
reversed_serials_data = serial_part
reversed_serials_data = serial_next
# bs=b''
# for x in reversed_serials_data:
# bs+=x.to_bytes(4,'little')
# # print(x.to_bytes(4,'little'))
# print('reversed_serials_data:\n',bs,bs.hex())
return reversed_serials_data
def serialStrToIntArray(serial:str):
serial=serial.split('-')
serial_array =[ int.from_bytes(bytes.fromhex(serial),'big') for i in range(4)]
return serial_array
def domain():
# uid=720957
print('please input your uid:')
uidstr=input()
if not uidstr:
uid=720957
print('uid:',uid)
else:
uid=int(uidstr)
numb=uid**3^0x323032796C6C6F73
serials_data=numbTotarget(numb)
redata=reverse_check_serial(serials_data, table2_41F8D0, table3_41E8D0)
result=[]
for x in redata:
result.append('%08x'%x)
print('serial:'+'-'.join(result))
if __name__=='__main__':
domain()
'''
uid: 720957
serial:6A9D679F-D851591D-0B943F6F-D3E95EDC
'''
``` 过程很详细,给LZ点赞!
作为新手 还是有很多不明白的地方
比如
上面黑色背景部分的代码 是用什么分析软件反编译得到 还是阅读汇编指令后对应打的代码?
IDA中是怎么分析COM Object的?是先从exe中解析出com组件的文件 再用ida分析吗 jackyyue_cn 发表于 2024-2-25 21:05
过程很详细,给LZ点赞!
作为新手 还是有很多不明白的地方
参数rename+自己重新写 请问内存的数据是怎么dump的呢,我unlicense后的程序无法正常的RegServer。 谢谢楼主,。。。。。。 感谢楼主分享,
请问内存的数据是怎么dump的呢,我unlicense后的程序无法正常的RegServer
页:
[1]