re | [MRCTF2020]Shit
嘛 这题直接给了源码 逻辑属于比较清晰的,还可以看到一种之前没见过的花指令,很有意思。
_asm
{
call sub1
_emit 0xE8
jmp label1
sub1:
add dword ptr[esp],1
retn
label1:
}
嘛,偷个懒直接看源码了
花指令全部去掉的话剩的就是这部分了:
#include<Windows.h>
#include<iostream>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int map[100],c=2;
int key[7]={'b','k','d','c','e','w'};
unsigned int ks[6]={0x8c2c133a,0xf74cb3f6,0xfedfa6f2,0xab293e3b,0x26cf8a2a,0x88a1f279};//{0x8c2cecc5,0xf74cb3f6,0xfedf590d,0xab293e3b,0x26cf75d5,0x88a1f279};
FARPROC proc=NULL;
int initHook()
{
HMODULE hModule=LoadLibraryA("Kernel32.dll");
if(hModule)
{
proc=GetProcAddress(hModule,"IsDebuggerPresent");
if(proc==NULL)
return -1;
}
return 0;
}
PDWORD update()
{
if(initHook()!=0)
exit(-1);
HANDLE hProcess=GetModuleHandle(NULL);
PIMAGE_DOS_HEADER dos_header=(PIMAGE_DOS_HEADER)hProcess;
PIMAGE_NT_HEADERS nt_header=(PIMAGE_NT_HEADERS)(dos_header->e_lfanew+(DWORD)hProcess);
IMAGE_OPTIONAL_HEADER* opt_header=&(nt_header->OptionalHeader);
PIMAGE_IMPORT_DESCRIPTOR iat=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hProcess+opt_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while(iat->FirstThunk)
{
PIMAGE_THUNK_DATA data=(PIMAGE_THUNK_DATA)(iat->FirstThunk+(DWORD)hProcess);
while(data->u1.Function)
{
if(IMAGE_SNAP_BY_ORDINAL(data->u1.AddressOfData))
{
data++;
continue;
}
if((DWORD)proc==data->u1.Function)
return &data->u1.Function;
data++;
}
iat++;
}
return NULL;
}
PDWORD table_addr=NULL;
int writeAddr(DWORD addr)
{
if(table_addr==NULL)
table_addr=update();
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi_thunk;
VirtualQuery(table_addr,&mbi_thunk,sizeof(MEMORY_BASIC_INFORMATION));
VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,PAGE_READWRITE,&mbi_thunk.Protect);
*table_addr=(DWORD)addr;
VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,mbi_thunk.Protect,&dwOldProtect);
return 0;
}
bool WINAPI CallBackProc()
{
writeAddr((DWORD)proc);
map[0]=2;c--;
key[0]='a';
key[1]='k';
key[2]='e';
key[3]='y';
key[4]='e';
key[5]='z';
if(IsDebuggerPresent())
{
MessageBoxW(NULL,L"U R Using Debugger!",L"U Suck!",MB_OK);
return true;
}
return false;
}
void sleep()
{
sleep();
}
int checkDebug()
{
if(*((unsigned char *)(*(DWORD*)(__readfsdword(0x18)+0x30))+0x2))
sleep();
return 0;
}
int doit=writeAddr((DWORD)CallBackProc),dd=checkDebug();
bool encode(char* ur_flag)
{
unsigned int k=0,bk=0;
for(int i=0;i<strlen(ur_flag);i+=4)
{
k=(((int)ur_flag[i])<<24)|(((int)ur_flag[i+1])<<16)|(((int)ur_flag[i+2])<<8)|((int)ur_flag[i+3]);
k=(k>>key[i/4]) | (k<<(32-key[i/4]));
k=((~(k>>16))&0x0000ffff) | (k<<16);
k=(1<<key[i/4])^k;
if(i>0)
k^=bk;
bk=k;
if(k!=ks[i/4])
return false;
}
return true;
}
void genKey()
{
int len=20,keylen=6,maxium=0;
int before;
srand(time(NULL));
for(int i=1;i<=len;i++)
{
map[i]=map[i-1]+rand()%5;
maxium=maxium>map[i]?maxium:map[i];
}
before=time(NULL);
for(int i=0;i<keylen;i++)
{
int step=0;
long long t=time(NULL);
int delta=t-before;
if(delta>maxium)
return;
for(int j=0;j<=len;j++)
if(delta<=map[j])
{
step=map[j];
break;
}
key[i]=(key[i]*c+step+i*3)%32;
before=t;
}
}
/*void decode()
{
unsigned int k=0,bk=0;
for(int i=5;i>=0;i--)
if(i>0)
ks[i]^=ks[i-1];
for(int i=0;i<24;i+=4)
{
k=ks[i/4];
k=(1<<key[i/4])^k;
k=((k>>16)) | ((~(k<<16))&0xffff0000);
k=((k<<key[i/4])) | (k>>(32-key[i/4]));
printf("%X\n",k);
}
}*/
int main()
{
char ur_flag[50];
cout<<"please input your flag:"<<endl;
cin>>ur_flag;
if(IsDebuggerPresent())
{
cout<<"U suck! 233333"<<endl;
Sleep(2000);
exit(0);
}
if(strlen(ur_flag)!=24)
{
cout<<"Wrong!"<<endl;
Sleep(2000);
exit(0);
}
genKey();
bool flag=encode(ur_flag);
//decode();
if(flag)
{
cout<<"U did it!"<<endl<<"GJ!"<<endl;
system("pause");
exit(0);
}
cout<<"Wrong!"<<endl;
Sleep(2000);
return 0;
}
然后不是有个反调试嘛,发现用od直接走就行了,,,根本没事。。。
然后动态调试出key:03 10 0d 04 13 0b
啊,然后不是有解密脚本吗,改一改就能用了。
exp:
#include <stdio.h>
int key[7]={0x03, 0x10, 0x0d, 0x04, 0x13, 0x0b};
unsigned int ks[6]={0x8c2c133a,0xf74cb3f6,0xfedfa6f2,0xab293e3b,0x26cf8a2a,0x88a1f279};
void decode()
{
unsigned int k=0,bk=0;
for(int i=5;i>=0;i--)
if(i>0)
ks[i]^=ks[i-1];
for(i=0;i<24;i+=4)
{
k=ks[i/4];
k=(1<<key[i/4])^k;
k=((k>>16)) | ((~(k<<16))&0xffff0000);
k=((k<<key[i/4])) | (k>>(32-key[i/4]));
//printf("%X\n",k);
for(int j=0; j < 4; j ++){
printf("%c", *((char*)&k+3-j));
}
}
}
int main(){
decode();
return 0;
}
嘛,没搞清用的是什么算法,弄清了补上。
overです。
本文来自博客园,作者:Mz1,转载请注明原文链接:https://www.cnblogs.com/Mz1-rc/p/14368677.html
如果有问题可以在下方评论或者email:mzi_mzi@163.com