1. 程式人生 > >關於KeyFile的破解,含註冊機原始碼

關於KeyFile的破解,含註冊機原始碼

程式來自於《加密與解密3》的第五章的PacMe.exe。書中並沒有給出C語言實現的加密與解密程式碼,自己花了一些時間,把程式碼還原了,並且寫了一個C語言的註冊機。

加密原理:正如書中所說,此程式是生成一個11x16的迷宮,其中*表示不通,.表示通,起點為C,終點為X。所經過的路徑的方向,每4個作為1位元組,成為加密的資料。

解密思路:通過IDA匯出程式的迷宮資料,通過尋路演算法,找到唯一路徑,然後按照KeyFile格式加密並生成KeyFile。

迷宮資料:

char Maze[] = { "****************"
							"C*......*...****"
							".*.****...*....*"
							".*..**********.*"
							"..*....*...*...*"
							"*.****.*.*...***"
							"*.*....*.*******"
							"..*.***..*.....*"
							".*..***.**.***.*"
							"...****....*X..*"
							"****************" };//11*16

先看下從程式裡反彙編出的解密函式:

bool KeyCode(const char *szFilename, char *pMaze) {//KwazyWeb.bit
	HANDLE hFile;
	if ((hFile = CreateFileA(szFilename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
		0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
		CloseHandle(hFile);
		return false;
	}
	DWORD dwByteRead;
	BYTE bUsersize;
	ReadFile(hFile, &bUsersize, 1, &dwByteRead, NULL);
	if (bUsersize == 0) {
		CloseHandle(hFile);
		return false;
	}
	//0x403288
	DWORD dwByteUser = 0;
	char szUserInfo[100];
	ReadFile(hFile, szUserInfo, bUsersize, &dwByteRead, NULL);
	//使用者名稱求和
	for (int i = 0; i < (int)bUsersize; i++)
		dwByteUser += szUserInfo[i];
	//0x4034e8
	BYTE szDataInfo[18];
	ReadFile(hFile, szDataInfo, 18, &dwByteRead, NULL);
	//異或資料
	for (int i = 0; i < 18; i++) 
		szDataInfo[i] = szDataInfo[i] ^ (BYTE)dwByteUser;
	int k;
	char *pos = &pMaze[16];
	for (int j = 0; j < 18; j++)
		for (int i = 8; i != 0;) {
			i -= 2;
			k = szDataInfo[j] >> i & 3;
			if (k == 0)
				pos = pos - 16;//↑
			else if (k == 1)//→
				pos++;
			else if (k == 2)//↓
				pos = pos + 16;
			else//←
				pos--;
		}
	//判斷是否到達位置X
		if (pos[0] != 'X'){
			CloseHandle(hFile);
			return false;
		}
	CloseHandle(hFile);
	return true;
}

註冊機實現(第一次寫註冊機,還專門學習了下尋路演算法):

void KeyGen(const char *szFilename, char *pMaze, const char *szName) {
	HANDLE hFile;
	if ((hFile = CreateFileA(szFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
		0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
		CloseHandle(hFile);
		return;
	}
	std::list<int> path;
	std::vector<int> pack;
	int len = lstrlenA(pMaze), pos;
	char *pMaze1 = new char[len + 1];
	memcpy(pMaze1, pMaze, len + 1);//包含'\0'
	for (pos = 0; pos < len; pos++)
		if (pMaze1[pos] == 'C')
			break;
	path.push_back(pos);
	Walk(pMaze1, pos / 16, pos - pos / 16 * 16, path);
	//計算序列值
	int i, j;
	pos = path.front();
	path.pop_front();
	while (!path.empty()) {
		i = path.front() / 16 - pos / 16;
		j = path.front() - path.front() / 16 * 16 - (pos - pos / 16 * 16);
		if (j == 0) {
			if (i > 0)
				pack.push_back(2);
			else if (i < 0)
				pack.push_back(0);
		}
		else if (i == 0) {
			if (j > 0)
				pack.push_back(1);
			else if (j < 0)
				pack.push_back(3);
		}
		pos = path.front();
		path.pop_front();
	}
	pos = lstrlenA(szName);
	len = 0;
	for (i = 0; i < pos; i++)
		len += szName[i];
	for (i = 0; i < (int)pack.size(); i += 4)
		path.push_back((pack[i] << 6 | pack[i + 1] << 4 | pack[i + 2] << 2 | pack[i + 3]) ^ (BYTE)len);
	WriteFile(hFile, &pos, 1, (DWORD *)&j, NULL);
	WriteFile(hFile, szName, pos, (DWORD *)&j, NULL);
	for (auto itr = path.begin(); itr != path.end(); itr++) 
		WriteFile(hFile, &(*itr), 1, (DWORD *)&j, NULL);
	delete[] pMaze1;
	CloseHandle(hFile);
}

其中尋路演算法函式Walk實現如下:

bool Walk(char *pMaze, int i, int j, std::list<int> &path) {
	if (pMaze[i * 16 + j] == 'X') 
		return true;
	int distX[] = { -1,0,1,0 }, distY[] = { 0,1,0,-1 };
	for (int k = 0; k < 4; k++) {
		if (i + distX[k] >= 0 && i + distX[k] < 11 && j + distY[k] >= 0 && j + distY[k] < 16
			&& (pMaze[(i + distX[k]) * 16 + j + distY[k]] == '.' || pMaze[(i + distX[k]) * 16 + j + distY[k]]=='X')) {//下一步通路
			pMaze[i * 16 + j] = '*';//當前封路
			path.push_back((i + distX[k]) * 16 + j + distY[k]);//下一步入棧
			if (!Walk(pMaze, i + distX[k], j + distY[k], path)) {
				path.pop_back();
				pMaze[i * 16 + j] = '.';//開路
				continue;
			}
			return true;
		}
	}
	return false;
}

Main函式測試如下:

int main(){
	KeyGen("key.bit", Maze, "Thanks, pediy!");//註冊機
	if (KeyCode("key.bit", Maze))//解碼
		printf("Valid Key file\n");
	else 
		printf("Contact me to get Key file\n");
	system("pause");
}

程式碼測試圖