// Mstest.cpp : Defines the entry point for the application.
//
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
#include "resource.h"
#include "des.h"
#include "x86il.h"

//#pragma comment (lib, "comctl32")
//#pragma comment (linker, "/ALIGN:0x1000")
//#pragma comment (linker, "/FILEALIGN:0x200")
//#pragma comment (linker, "/ENTRY:WinMain")

int Bits = 0;
BYTE AnaI[32];
int nPfx;
int iModRM;
int ISize;
int ILength;
DWORD OpCode;
DWORD Reg[8] = {0};
DWORD StackPointer;
BYTE StackBuf[0x80000];

DWORD Decode(BYTE *InBuf,BYTE *OutBuf)
{
	BYTE Key[8] = {0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89};
	BYTE TmpBuf[0x400];
	int Len;
	int i;
	int x = 0;
	BYTE c;

	Len = strlen((char *)InBuf);
	if (Len < 0x400)
	{
		for (i=0;i<Len;i++)
		{
			c = InBuf[i];
			if (c == 0x01)
			{
				i++;
				x++;
				if (InBuf[i] == 0x01)
				{
					TmpBuf[i-x] = 0;
				}
				else if(InBuf[i] == 0x02)
				{
					TmpBuf[i-x] = c;
				}				
			}
			else
			{
				TmpBuf[i-x] = c;
			}
		}
		TmpBuf[i-x] = 0;

		Len -= x;
		for (i=0;i<Len/8;i++)
		{
			Des(&TmpBuf[i*8], &OutBuf[i*8], Key, DECRYPT);
		}
		for (i=Len/8*8;i<Len;i++)
		{
			OutBuf[i] = TmpBuf[i];
		}
		OutBuf[i] = 0;
	}

	return 1;
}

DWORD FindDecoder(DWORD Addr,DWORD Len)
{
	DWORD i;

	for (i=0;i<Len-0x70;i++)
	{
		if ((*(DWORD *)(Addr+i) == 0x0424548B) && (*(DWORD *)(Addr+i+4) == 0x8B575655))
		{
			if ((*(DWORD *)(Addr+i+8) == 0xFFC983FA) && (*(DWORD *)(Addr+i+12) == 0xF633C033))
			{
				return (Addr+i);
			}
		}
	}

	return 0;
}

DWORD GetStrings(char *szInFile,char *szOutFile)
{
	HANDLE hFile;
	HANDLE hMap;
	DWORD lpMap;
	IMAGE_NT_HEADERS *NtHeader;
	IMAGE_SECTION_HEADER *SecHeader;
	DWORD CodeAddr;
	DWORD CodeLen;
	DWORD DecoderAddr;
	DWORD j;
	BYTE InBuf[0x400];
	BYTE OutBuf[0x400];
	DWORD dwTmp;
	FILE *FileOut;

	hFile = CreateFile(szInFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (INVALID_HANDLE_VALUE != hFile)
	{
		if (hMap = CreateFileMapping(hFile,NULL,PAGE_READONLY|SEC_IMAGE,0,0,NULL))
		{
			if (lpMap = (DWORD)MapViewOfFile(hMap,FILE_MAP_READ,0,0,0))
			{
				NtHeader = (IMAGE_NT_HEADERS *)(*(DWORD *)(lpMap+0x3C) + lpMap);
				SecHeader = IMAGE_FIRST_SECTION32(NtHeader);
				CodeAddr = SecHeader->VirtualAddress + lpMap;
				CodeLen = SecHeader->Misc.VirtualSize;
				if (DecoderAddr = FindDecoder(CodeAddr,CodeLen))
				{
					FileOut = fopen(szOutFile, "w");
					fclose(FileOut);
					StackPointer = (DWORD)StackBuf + 0x40000;
					Reg[0] = 0;
					Reg[1] = 0;
					Reg[2] = 0;
					Reg[3] = 0;
					Reg[4] = StackPointer;
					Reg[5] = 0;
					Reg[6] = 0;
					Reg[7] = 0;
					j=0;
					while (j < CodeLen)
					{
						ILength = X86IL(Bits, (BYTE *)(CodeAddr+j), AnaI, &nPfx, &iModRM, &ISize);
						OpCode = *(DWORD *)(CodeAddr+j);

						if ((BYTE)OpCode == 0xC3)
						{
							StackPointer = (DWORD)StackBuf + 0x40000;
							Reg[4] = StackPointer;
						}
						else if ((BYTE)OpCode == 0xC2)
						{
							StackPointer = (DWORD)StackBuf + 0x40000;
							Reg[4] = StackPointer;
						}
						else if (((BYTE)OpCode & 0xF0)  == 0xB0)
						{
							switch ((BYTE)OpCode & 0x0F)
							{
							case 0x00:
								Reg[0] &= 0xFFFFFF00;
								Reg[0] |= *(BYTE *)(CodeAddr+j+1);
								break;
							case 0x01:
								Reg[1] &= 0xFFFFFF00;
								Reg[1] |= *(BYTE *)(CodeAddr+j+1);
								break;
							case 0x02:
								Reg[2] &= 0xFFFFFF00;
								Reg[2] |= *(BYTE *)(CodeAddr+j+1);
								break;
							case 0x03:
								Reg[3] &= 0xFFFFFF00;
								Reg[3] |= *(BYTE *)(CodeAddr+j+1);
								break;
							case 0x04:
								Reg[0] &= 0xFFFF00FF;
								Reg[0] |= *(BYTE *)(CodeAddr+j+1) << 0x08;
								break;
							case 0x05:
								Reg[1] &= 0xFFFF00FF;
								Reg[1] |= *(BYTE *)(CodeAddr+j+1) << 0x08;
								break;
							case 0x06:
								Reg[2] &= 0xFFFF00FF;
								Reg[2] |= *(BYTE *)(CodeAddr+j+1) << 0x08;
								break;
							case 0x07:
								Reg[3] &= 0xFFFF00FF;
								Reg[3] |= *(BYTE *)(CodeAddr+j+1) << 0x08;
								break;
							default:
								Reg[(BYTE)OpCode &0x07] = *(DWORD *)(CodeAddr+j+1);
								break;
							}
						}
						else if (((BYTE)OpCode & 0xF8)  == 0x50)
						{
							Reg[4] -= 4;

							dwTmp = Reg[4] - (DWORD)StackBuf;
							if (dwTmp > 0x80000)
							{
								StackPointer = (DWORD)StackBuf + 0x40000;
								Reg[4] = StackPointer;
							}
							else
							{								
								StackPointer = Reg[4];
								*(DWORD *)StackPointer = Reg[(BYTE)OpCode & 0x07];
							}
						}
						else if (((BYTE)OpCode & 0xF8)  == 0x58)
						{
							dwTmp = Reg[4] - (DWORD)StackBuf;
							if (dwTmp > 0x80000)
							{
								StackPointer = (DWORD)StackBuf + 0x40000;
								Reg[4] = StackPointer;
							}
							else
							{
								StackPointer = Reg[4];
								Reg[(BYTE)OpCode & 0x07] = *(DWORD *)StackPointer;
								Reg[4] += 4;
							}
						}
						else if ((BYTE)OpCode == 0x32)
						{
							if ((WORD)OpCode == 0xC032)
							{
								Reg[0] &= 0xFFFFFF00;
							}
							else if ((WORD)OpCode == 0xC932)
							{
								Reg[1] &= 0xFFFFFF00;
							}
							else if ((WORD)OpCode == 0xD232)
							{
								Reg[2] &= 0xFFFFFF00;
							}
							else if ((WORD)OpCode == 0xDB32)
							{
								Reg[3] &= 0xFFFFFF00;
							}
							else if ((WORD)OpCode == 0xE432)
							{
								Reg[0] &= 0xFFFF00FF;
							}
							else if ((WORD)OpCode == 0xED32)
							{
								Reg[1] &= 0xFFFF00FF;
							}
							else if ((WORD)OpCode == 0xF632)
							{
								Reg[2] &= 0xFFFF00FF;
							}
							else if ((WORD)OpCode == 0xFF32)
							{
								Reg[3] &= 0xFFFF00FF;
							}
						}
						else if (((BYTE)OpCode == 0x31) || ((BYTE)OpCode == 0x33))
						{
							if (((WORD)OpCode == 0xC033) || ((WORD)OpCode == 0xC031))
							{
								Reg[0] = 0;
							}
							else if (((WORD)OpCode == 0xC933) || ((WORD)OpCode == 0xC931))
							{
								Reg[1] = 0;
							}
							else if (((WORD)OpCode == 0xD233) || ((WORD)OpCode == 0xD231))
							{
								Reg[2] = 0;
							}
							else if (((WORD)OpCode == 0xDB33) || ((WORD)OpCode == 0xDB31))
							{
								Reg[3] = 0;
							}
							else if (((WORD)OpCode == 0xE433) || ((WORD)OpCode == 0xE431))
							{
								Reg[4] = 0;
							}
							else if (((WORD)OpCode == 0xED33) || ((WORD)OpCode == 0xED31))
							{
								Reg[5] = 0;
							}
							else if (((WORD)OpCode == 0xF633) || ((WORD)OpCode == 0xF631))
							{
								Reg[6] = 0;
							}
							else if (((WORD)OpCode == 0xFF33) || ((WORD)OpCode == 0xFF31))
							{
								Reg[7] = 0;
							}
						}
						else if ((WORD)OpCode  == 0xC481)
						{
							Reg[4] += *(DWORD *)(CodeAddr+j+2);
						}
						else if ((WORD)OpCode  == 0xC483)
						{
							Reg[4] += *(char *)(CodeAddr+j+2);
						}
						else if ((WORD)OpCode  == 0xEC81)
						{
							Reg[4] -= *(DWORD *)(CodeAddr+j+2);
						}
						else if ((WORD)OpCode  == 0xEC83)
						{
							Reg[4] -= *(char *)(CodeAddr+j+2);
						}
						else if ((BYTE)OpCode  == 0x68)
						{
							Reg[4] -= 4;
							StackPointer = Reg[4];
							*(DWORD *)StackPointer = *(DWORD *)(CodeAddr+j+1);
						}
						else if ((BYTE)OpCode  == 0x6A)
						{
							Reg[4] -= 4;
							StackPointer = Reg[4];
							*(DWORD *)StackPointer = *(char *)(CodeAddr+j+1);
						}
						else if ((OpCode & 0x00FFFFFF)  == 0x2444C6)
						{
							dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
							if (dwTmp > 0x80000)
							{
								StackPointer = (DWORD)StackBuf + 0x40000;
								Reg[4] = StackPointer;
							}
							else
							{
								*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = *(BYTE *)(CodeAddr+j+4);
							}
						}
						else if ((OpCode & 0x00FFFFFF)  == 0x2484C6)
						{
							dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
							if (dwTmp > 0x80000)
							{
								StackPointer = (DWORD)StackBuf + 0x40000;
								Reg[4] = StackPointer;
							}
							else
							{
								*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = *(BYTE *)(CodeAddr+j+7);
							}
						}
						else if ((OpCode & 0x00FF00FF)  == 0x24008D)
						{
							switch ((BYTE)(OpCode >> 8))
							{
							case 0x84:
								Reg[0] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0x8C:
								Reg[1] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0x94:
								Reg[2] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0x9C:
								Reg[3] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0xA4:
								Reg[4] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0xAC:
								Reg[5] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0xB4:
								Reg[6] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0xBC:
								Reg[7] = Reg[4] + *(DWORD *)(CodeAddr+j+3);
								break;
							case 0x44:
								Reg[0] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x4C:
								Reg[1] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x54:
								Reg[2] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x5C:
								Reg[3] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x64:
								Reg[4] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x6C:
								Reg[5] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x74:
								Reg[6] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							case 0x7C:
								Reg[7] = Reg[4] + *(char *)(CodeAddr+j+3);
								break;
							default:
								break;
							}
						}
						else if ((OpCode & 0x00FF00FF)  == 0x240088)
						{
							switch ((BYTE)(OpCode >> 8))
							{
							case 0x84:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)Reg[0];
								}
								break;
							case 0x8C:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)Reg[1];
								}
								break;
							case 0x94:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)Reg[2];
								}
								break;
							case 0x9C:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)Reg[3];
								}
								break;
							case 0xA4:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)(Reg[0] >> 0x08);
								}
								break;
							case 0xAC:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)(Reg[1] >> 0x08);
								}
								break;
							case 0xB4:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)(Reg[2] >> 0x08);
								}
								break;
							case 0xBC:
								dwTmp = Reg[4] + *(DWORD *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(DWORD *)(CodeAddr+j+3)) = (BYTE)(Reg[3] >> 0x08);
								}
								break;
							case 0x44:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)Reg[0];
								}
								break;
							case 0x4C:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)Reg[1];
								}
								break;
							case 0x54:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)Reg[2];
								}
								break;
							case 0x5C:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)Reg[3];
								}
								break;
							case 0x64:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)(Reg[0] >> 0x08);
								}
								break;
							case 0x6C:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)(Reg[1] >> 0x08);
								}
								break;
							case 0x74:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)(Reg[2] >> 0x08);
								}
								break;
							case 0x7C:
								dwTmp = Reg[4] + *(char *)(CodeAddr+j+3) - (DWORD)StackBuf;
								if (dwTmp > 0x80000)
								{
									StackPointer = (DWORD)StackBuf + 0x40000;
									Reg[4] = StackPointer;
								}
								else
								{
									*(BYTE *)(Reg[4] + *(char *)(CodeAddr+j+3)) = (BYTE)(Reg[3] >> 0x08);
								}
								break;
							default:
								break;
							}
						}
						else if ((BYTE)OpCode == 0xE8)
						{
							if ((*(DWORD *)(CodeAddr+j+1) + 5 + j) == (DecoderAddr - CodeAddr))
							{
								dwTmp = Reg[4] - (DWORD)StackBuf;
								if (dwTmp < 0x80000)
								{
									dwTmp = *(DWORD *)Reg[4];
									if (dwTmp < ((DWORD)StackBuf+0x80000))
									{
										strcpy((char *)InBuf,(char *)dwTmp);
										Decode(InBuf,OutBuf);
										FileOut = fopen(szOutFile, "a");
										fprintf(FileOut, "%s\r\n", OutBuf);
										fclose(FileOut);
									}
								}
							}
						}
						dwTmp = Reg[4] - (DWORD)StackBuf;
						if (dwTmp > 0x80000)
						{
							StackPointer = (DWORD)StackBuf + 0x40000;
							Reg[4] = StackPointer;
						}
						
						j += ILength;
					}
					printf("\n处理结束,生成输出文件:%s\n",szOutFile);
				}
				UnmapViewOfFile((LPVOID)lpMap);
			}
			CloseHandle(hMap);
		}
		CloseHandle(hFile);
	}
	else
	{
		printf("\nCan not open file:%s\n",szOutFile);
	}

	return 1;
}

/*
int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if (uMsg == WM_COMMAND)
	{
		if (LOWORD(wParam) == ID_TEST)
		{
			Unpack(hDlg);
			return 1;
		}
		else if (LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, wParam);
			return 1;
		}
	} 

	return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	InitCommonControls();
	DialogBox((HINSTANCE)0x400000, MAKEINTRESOURCE(IDD_MSTEST), NULL, (DLGPROC)DlgProc);
	return 0;
}
*/
int main(int argc, char* argv[])
{
	char szInFile[MAX_PATH];
	char szOutFile[MAX_PATH];

	if (argc > 1)
	{
		memset(szInFile,0,MAX_PATH);
		memset(szOutFile,0,MAX_PATH);
		strcpy(szInFile,argv[1]);
		strcpy(szOutFile,"out.txt");
		
		GetStrings(szInFile,szOutFile);
	}
	else
	{
	}
	
	return 1;
}
