reverse03:
author @deadfish
闲着无聊 做了学校的ctf平台的一题(之前遗留了)
先uxp脱壳 然后拖进ida
主要代码如下
falgDug = 0;
inUser = 0; // [bp-14h] 开始依次 48, 52, 49, 55, 53, 49, 51, 48, 48, 49, 51, 50
v_13h = 0;
v_Fh = 0;
v22 = 0;
v23 = 0;
inPass = 0;
v13 = 0;
v14 = 0;
v15 = 0;
v16 = 0;
v17 = 0;
v18 = 0;
printf("输入用户名:");
scanf("%15s", &inUser);
printf("\n");
printf("输入密码:");
scanf("%25s", &inPass);
iU = strlen(&inUser);
for ( i = 0; i < iU; ++i )
{
if ( *(&inUser + i) < '0' || *(&inUser + i) > '9' )
{
printf("用户名必须为数字");
goto LABEL_13;
}
}
v9 = GetTickCount();
v5 = &loc_401052;
IsOver = 0x40;
do
{ // check int
if ( !IsOver )
break; // 检测int3断点防止调试
getInt3 = *(_BYTE *)v5 == 0xCCu;
v5 = (char *)v5 + 1;
--IsOver;
}
while ( !getInt3 );
if ( getInt3 )
falgDug = 1;
isInt = (GetTickCount() - v9) / 0x3E8 > 1; // 判断时间,防止调试
produceAlph1(falgDug, (int)&inUser, isInt);
produceAlph2((char *)&v_13h + 3);
produceAlph3((char *)&v_Fh + 3);
checkPassword(&inPass);
LABEL_13:
system("pause");
return 0;
看到解密的数组列表
alph1=’onhtxdsqvpzcrefjigklfzbapvdqsxzrcefimlku’
alph2=’zscbmdvholblzftuhsxsbchanrcdqjvqfinotcbu’
alph3=’pzywrvdcbqeuafsxgmlitnkopvdqsxtdnapcuwys’
这里是在ida里算偏移算出来的
username:041751300132
对应位置为
bp-[h] 14 13 12 11 10 0f 0e 0d 0c 0b 0a 09
// 48, 52, 49, 55 53, 49, 51, 48 48, 49, 51, 50
注意到
produceAlph1中有个检测int3断点的程序,防止OD调试
v9 = GetTickCount();
v5 = &loc_401052;
IsOver = 0x40;
do
{ // check int
if ( !IsOver )
break; // 检测int3断点防止调试
getInt3 = *(_BYTE *)v5 == 0xCCu;
v5 = (char *)v5 + 1;
--IsOver;
}
while ( !getInt3 );
if ( getInt3 )
falgDug = 1;
###IDA伪指令解析错误:
怎么写脚本调都不对,问了学长,flag对了,但是伪C代码逻辑有改地方不对
这个地方:
f_8 = *((_BYTE *)&aIdaq64_exe[5 * (isDbg + 2 * (unsigned __int8)isFsd) + 2] + *(_BYTE *)pThis);
反过去汇编才发现ida F5解析错了 应该是:
*((_BYTE *)&aIdaq64_exe[2 * 5 * (isDbg + 2 * (unsigned __int8)isFsd)]才对吧
.text:00401420 var_4 = dword ptr -4
.text:00401420
.text:00401420 push ebp
.text:00401421 mov ebp, esp
.text:00401423 push ecx
.text:00401424 push ebx
.text:00401425 push esi
.text:00401426 mov esi, ecx
.text:00401428 mov [ebp+var_4], 0 ; var_4 = 0
.text:0040142F mov cl, 1
.text:00401431 mov eax, large fs:'0'
.text:00401437 mov eax, [eax+68h] ; eax += fs:'0'
.text:0040143A mov [ebp+var_4], eax
.text:0040143D test byte ptr [ebp+var_4], 'p'
.text:00401441 mov eax, 0
.text:00401446 movzx ebx, cl ; if (var_4 == 'p') ebx = 1
.text:00401446 ; else ebx = 0
.text:00401449 cmovnz ebx, eax
.text:0040144C call ds:IsDebuggerPresent
.text:00401452 neg eax ; if (IsDebuggerPresent) eax = 1
.text:00401452 ; else eax = 0
.text:00401454 movzx ecx, bl ; 设isFsd = bl
.text:00401457 sbb eax, eax
.text:00401459 neg eax ; 设isDbg = eax
.text:0040145B lea eax, [eax+ecx*2] ; eax = isDbg + 2*isFsd
.text:0040145E lea ecx, [eax+eax*4] ; ecx = 5*(eaxL) = 5*(isDbg + 2*isFsd)
.text:00401461 movsx eax, byte ptr [esi]
.text:00401464 movzx eax, byte ptr [eax+ecx*2+4021A0h] ; 2*ecx = 2*5*(isDbg + 2*isFsd) = 10*(isDbg + 2*isFsd)
.text:0040146C mov f_8, al ; 当 isDbg=0 isFsd=1 该值为 10*2-20
.text:0040146C ; 和ad3_1 = 0
.text:0040146C ; ad3_2 = 1
.text:0040146C ; ad3 = 5*(ad3_1 + 2 * ad3_2 + 2) = 20 一致
.text:00401471 movsx eax, byte ptr [esi+1]
.text:00401475 movzx eax, byte ptr [eax+ecx*2+4021A0h]
.text:0040147D mov f_9, al
.text:00401482 movsx eax, byte ptr [esi+2]
.text:00401486 movzx eax, byte ptr [eax+ecx*2+4021A0h]
.text:0040148E mov f_10, al
.text:00401493 movsx eax, byte ptr [esi+3]
.text:00401497 pop esi
.text:00401498 pop ebx
.text:00401499 movzx eax, byte ptr [eax+ecx*2+4021A0h]
.text:004014A1 mov f_11, al
.text:004014A6 mov esp, ebp
.text:004014A8 pop ebp
.text:004014A9 retn
.text:004014A9 produceAlph3 endp
(
neg r 指令的结果是设置Carry Flag, 也就是借位的标志位. 因为neg r的操作语义是0 - r, 零减去任何非零的数,都会产生"借位"的. 当然这里r寄存器中的值也被改掉了,不过没关系, 反正它都要被稍后的指令再改掉的.
sbb r, r 指令设置r为零或者-1. 因为语义为用一个值去减掉它自身, 结果当然是零啰. 但是,这样做会把carry flag一起给减掉的, 该指令的公式是
r – r – CF –> r
为零(ZF=1) CMOVZ AX, BX
CMOVZ r32, r/m32 CMOVZ EAX, EB
)