之前在笔记本上从来没出现过这个问题, 相同的安装文件. 已经打了protel99seservicepack6的补丁. 换了4核的台式机基本每天都有几次...
这个问题在网上搜索, 回答多是不能用太好的机器否则Protel 99 SE 就会有很多问题, 经过分析实际还真是这样的.
Od载入 Client99SE.exe 断点到 Kernel32->RaiseException, 因为这是个delphi未处理异常. 运行进程等待 Client99SE.exe 抛出异常.
当调用RaiseException 时查看调用栈定位到函数
0DF61357 55 push ebp
0DF61358 68 9414F60D push 0DF61494
0DF6135D 64:FF30 push dword ptr fs:[eax]
0DF61360 64:8920 mov dword ptr fs:[eax], esp
0DF61363 C606 00 mov byte ptr [esi], 0
0DF61366 E8 CD03E9FF call <jmp.&kernel32.GetTickCount>
0DF6136B 8BD8 mov ebx, eax
0DF6136D 8D85 FCFEFFFF lea eax, dword ptr [ebp-104]
0DF61373 50 push eax
0DF61374 A1 7CF1F70D mov eax, dword ptr [DF7F17C]
0DF61379 83C0 11 add eax, 11
0DF6137C 8985 E4FEFFFF mov dword ptr [ebp-11C], eax
0DF61382 C685 E8FEFFFF 04 mov byte ptr [ebp-118], 4
0DF61389 C685 ECFEFFFF 7E mov byte ptr [ebp-114], 7E
0DF61390 C685 F0FEFFFF 02 mov byte ptr [ebp-110], 2
0DF61397 899D F4FEFFFF mov dword ptr [ebp-10C], ebx
0DF6139D C685 F8FEFFFF 00 mov byte ptr [ebp-108], 0
0DF613A4 8D95 E4FEFFFF lea edx, dword ptr [ebp-11C]
0DF613AA B9 02000000 mov ecx, 2
0DF613AF B8 AC14F60D mov eax, 0DF614AC ; ASCII "%s\%s%x.tmp"
0DF613B4 E8 0703E9FF call <jmp.&Vcl50.Sysutils::Format>
0DF613B9 8B95 FCFEFFFF mov edx, dword ptr [ebp-104]
0DF613BF 8D85 00FFFFFF lea eax, dword ptr [ebp-100]
0DF613C5 B9 FF000000 mov ecx, 0FF
0DF613CA E8 71FEE8FF call <jmp.&Vcl50.System::LStrToString>
0DF613CF EB 69 jmp short 0DF6143A
0DF613D1 E8 6203E9FF call <jmp.&kernel32.GetTickCount>
0DF613D6 8BD8 mov ebx, eax
0DF613D8 8D85 E0FEFFFF lea eax, dword ptr [ebp-120]
0DF613DE 50 push eax
0DF613DF A1 7CF1F70D mov eax, dword ptr [DF7F17C]
0DF613E4 83C0 11 add eax, 11
0DF613E7 8985 E4FEFFFF mov dword ptr [ebp-11C], eax
0DF613ED C685 E8FEFFFF 04 mov byte ptr [ebp-118], 4
0DF613F4 C685 ECFEFFFF 7E mov byte ptr [ebp-114], 7E
0DF613FB C685 F0FEFFFF 02 mov byte ptr [ebp-110], 2
0DF61402 899D F4FEFFFF mov dword ptr [ebp-10C], ebx
0DF61408 C685 F8FEFFFF 00 mov byte ptr [ebp-108], 0
0DF6140F 8D95 E4FEFFFF lea edx, dword ptr [ebp-11C]
0DF61415 B9 02000000 mov ecx, 2
0DF6141A B8 C014F60D mov eax, 0DF614C0 ; ASCII "%s\s%x%.tmp"
0DF6141F E8 9C02E9FF call <jmp.&Vcl50.Sysutils::Format>
0DF61424 8B95 E0FEFFFF mov edx, dword ptr [ebp-120]
0DF6142A 8D85 00FFFFFF lea eax, dword ptr [ebp-100]
0DF61430 B9 FF000000 mov ecx, 0FF
0DF61435 E8 06FEE8FF call <jmp.&Vcl50.System::LStrToString>
0DF6143A 8D85 DCFEFFFF lea eax, dword ptr [ebp-124]
0DF61440 8D95 00FFFFFF lea edx, dword ptr [ebp-100]
0DF61446 E8 EDFDE8FF call <jmp.&Vcl50.System::LStrFromString>
0DF6144B 8B85 DCFEFFFF mov eax, dword ptr [ebp-124]
0DF61451 E8 B201E9FF call <jmp.&Vcl50.Sysutils::FileExists>
0DF61456 84C0 test al, al
0DF61458 ^ 0F85 73FFFFFF jnz 0DF613D1
0DF6145E 8BC6 mov eax, esi
0DF61460 8D95 00FFFFFF lea edx, dword ptr [ebp-100]
0DF61466 E8 2DFCE8FF call <jmp.&Vcl50.System::PStrCpy>
0DF6146B 33C0 xor eax, eax
0DF6146D 5A pop edx
0DF6146E 59 pop ecx
0DF6146F 59 pop ecx
0DF61470 64:8910 mov dword ptr fs:[eax], edx
0DF61473 68 9B14F60D push 0DF6149B
0DF61478 8D85 DCFEFFFF lea eax, dword ptr [ebp-124]
0DF6147E BA 02000000 mov edx, 2
0DF61483 E8 90FDE8FF call <jmp.&Vcl50.System::LStrArrayClr>
0DF61488 8D85 FCFEFFFF lea eax, dword ptr [ebp-104]
0DF6148E E8 7DFDE8FF call <jmp.&Vcl50.System::LStrClr>
0DF61493 C3 retn
0DF61494 ^ E9 3FFDE8FF jmp <jmp.&Vcl50.System::HandleFinally>
0DF61499 ^ EB DD jmp short 0DF61478
0DF6149B 5E pop esi
0DF6149C 5B pop ebx
0DF6149D 8BE5 mov esp, ebp
0DF6149F 5D pop ebp
0DF614A0 C3 retn
堆栈上有一块字符串
0013DD1C 0F817B8C ASCII "C:\PROGRA~1\DESIGN~1\\System\Temp\~35C52FB.tmp"
问题出在第二个调用format函数时给予的第一个参数 "%s\s%x%.tmp" 上.
用ida插件转换到c代码
int __fastcall sub_571334(int a1)
{
int v1; // esi@1
int v2; // ST04_4@1
DWORD v4; // eax@1
DWORD v5; // eax@2
int v6; // [sp+8h] [bp-124h]@1
int v7; // [sp+Ch] [bp-120h]@1
int v8; // [sp+28h] [bp-104h]@1
int v9; // [sp-Ch] [bp-138h]@1
int v10; // [sp+10h] [bp-11Ch]@1
char v11; // [sp+14h] [bp-118h]@1
char v12; // [sp+18h] [bp-114h]@1
char v13; // [sp+1Ch] [bp-110h]@1
DWORD v14; // [sp+20h] [bp-10Ch]@1
char v15; // [sp+24h] [bp-108h]@1
char v16; // [sp+2Ch] [bp-100h]@1
v6 = 0;
v7 = 0;
v8 = 0;
v1 = a1;
v2 = *MK_FP(__FS__, 0);
*MK_FP(__FS__, 0) = &v9;
*(_BYTE *)a1 = 0;
v4 = GetTickCount();
v10 = dword_58F17C + 17;
v11 = 4;
v12 = 126;
v13 = 2;
v14 = v4;
v15 = 0;
Sysutils__Format(&str__s__s_x_tmp[1], &v10, &v8);
System____linkproc___LStrToString(&v16, v8);
while ( 1 )
{
System____linkproc___LStrFromString(&v6, &v16);
if ( !(unsigned __int8)Sysutils__FileExists(v6) )
break;
v5 = GetTickCount();
v10 = dword_58F17C + 17;
v11 = 4;
v12 = 126;
v13 = 2;
v14 = v5;
v15 = 0;
Sysutils__Format(&str__s_s_x__tmp[1], &v10, &v7);
System____linkproc___LStrToString(&v16, v7);
}
System____linkproc___PStrCpy(v1, &v16);
*MK_FP(__FS__, 0) = v2;
System____linkproc___LStrArrayClr(&v6, 2);
return System____linkproc___LStrClr(&v8);
}
可以看到这个函数用来完成生成不重复的随机文件名, 当机器太快硬盘太快时GetTickCount返回的值可能在两次调用中相同, 就会调用第二个format发生这个异常 因为Sysutils__Format(&str__s_s_x__tmp[1], &v10, &v7);处参数是错误的.
Ps:我这c盘就一垃圾ssd...
只要补丁字符串 "%s\s%x%.tmp" 为 "%s\%s%x.tmp" 就可以了.
25735C732578252E746D70 -> 25735C257325782E746D70
原来是写 Protel 99 SE 的大神当年没测试到...
protel.99.se.sp6-patch.rar
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)