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です。

posted @ 2021-02-03 18:18  Mz1  阅读(318)  评论(1编辑  收藏  举报