拿到题目,发现有upx壳,先去壳,然后丢入IDA 分析
看到这里我们应该先了解一下关于Windows多线程的知识
CreateThread是一种微软在Windows API中提供了建立新的线程的函数,该函数在主线程的基础上创建一个新线程。线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。
可以看出主函数中创建了2个子线程,我们分别进行分析
StartAddress:
这里我们回到main函数中打开sub_411190()函数可以找到Source的的赋值
WaitForSingleObject
WaitForSingleObject是一种Windows API函数,当等待仍在挂起状态时,句柄被关闭,那么函数行为是未定义的。该句柄必须具有 SYNCHRONIZE 访问权限。
WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。
ReleaseMutex
ReleaseMutex是一种线性指令,具有释放线程拥有的互斥体的控制权。
线程也能告诉系统,它不想在某个时间段内被调度。
这是通过调用Sleep函数来实现的:
VOID Sleep(DWORD dwMilliseconds);
该函数可使线程暂停自己的运行,直到dwMilliseconds过去为止。
因此这两个线程是交替进行的,现在我们对第一个线程进行分析:
(这里如果用IDA7.5可以不用平衡堆栈就可以F5,用别的版本可能需要平衡堆栈)
dword_418008(也就是a2)的初始值是0x1D,也就是倒序遍历字符串,逆向逻辑也很简单,简单分析一下即可。
然后我们再看一下第二个线程发现除了 - -dword_418008 什么也没干。
这样就好办了,就是在dword_418008为奇数时,进行线程1,偶数时进行线程2,直到dword_418008=-1
整理好思路后写出脚本
#include
using namespace std;
char flag[100]="TOiZiZtOrYaToUwPnToBsOaOapsyS";
string key="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
int main()
{
for(int i=28;i>=0;i--)
{
if(i%2==0) continue;
for(int j=0;j<key.length();j++)
if(key[j]==flag[i])
{
if(flag[i]>=65&&flag[i]<=90)
{
flag[i]=j+96;
break;
}
else
{
flag[i]=j+38;
break;
}
}
}
for(int i=0;i<=28;i++) cout<<(char)flag[i];
return 0;
}
得到flag:ThisisthreadofwindowshahaIsES
但是交上去发现不对,重新看了一下比较函数发现虽然flag有30位,但是只比较了29位,一个一个字母试一试,发现最后一个字符为“E”。
flag{ThisisthreadofwindowshahaIsESE}