Algorithms of decryption *.bmd files

Algorithms of decryption *.bmd files

In practice reverse engineering, I decided to start to decrypt Item.bmd. Actually that’s a little code to decrypt the file Item.bmd.
By the way, main 1.07x (and versions above, may still be a couple of versions below, I have not tested it) before you start decoding file with XorEnc3, main decode something like a key, I have no idea what kind of key …
Below is the actual code and decipher the key. This key is useless without it you can decrypt the file Item.bmd, in general reversal of all that was in the code.
The function gets the last argument like a key: DecryptKey ((int) pDstBuf, ITEM_TOTAL_SIZE, 0xE2F1U);
So, the return value is compared with the key EncKey and only after comparing the two keys to decrypt a file. (Well, at least as arranged with WebZen).
The structures may not be correct, so if you know the size and structure field names, I would be grateful for the help

* Note: Without this key, too, can decrypt the file, so simply arranged in webzen.

The code of decryption key

Before XorEnc3

Spoiler:
Code:
int EncKey;
GetFileSize(&EncKey, 1, 4, fp);
Code:
int DecryptKey(int pSrcBuf, int Size, unsigned short EncKey)
{
  int Dst;
  int DecryptedKey = EncKey << 9;

  for (unsigned int i = 0; i <= Size - 4; i += 4)
  {
   memcpy(&Dst, (const void*)(i + pSrcBuf), 4U);

   int rest = (EncKey + (i >> 2)) % 2;

   if (rest)
   {
	if (rest == 1)
	 DecryptedKey += Dst;
   }
   else 
   {
	DecryptedKey ^= Dst;
   }
   
   if (!(i % 10)) 
	DecryptedKey ^= (unsigned int)(DecryptedKey + EncKey) >> ((i >> 2) % 8 + 1);
 }
 return DecryptedKey;
}

ALL DECRYPTED FILES FOR VERSION 1.07X (for lower version, and probably newer versions of files, but not for all)

Item.bmd.

Spoiler:
Code:
#include <iostream>

#include <stdio.h>
#include <conio.h>
#include <windows.h>

const int ITEM_LINE_SIZE = 84;

struct ItemEx
{
  char ItemName[30];
  BYTE b31;
  BYTE b32;
  BYTE b33;
  BYTE b34;
  BYTE b35;
  BYTE b36;
  BYTE b37;
  BYTE b38;
  BYTE b39;
  BYTE b40;
  BYTE b41;
  BYTE b42;
  BYTE b43;
  BYTE b44;
  BYTE b45;
  BYTE b46;
  BYTE b47;
  BYTE b48;
  BYTE b49;
  BYTE b50;
  BYTE b51;
  BYTE b52;
  BYTE b53;
  BYTE b54;
  BYTE b55;
  BYTE b56;
  BYTE b57;
  BYTE b58;
  BYTE b59;
  BYTE b60;
  BYTE b61;
  BYTE b62;
  BYTE b63;
  BYTE b64;
  BYTE b65;
  BYTE b66;
  BYTE b67;
  BYTE b68;
  BYTE b69;
  BYTE b70;
  BYTE b71;
  BYTE b72;
  BYTE b73;
  BYTE b74;
  BYTE b75;
  BYTE b76;
  BYTE b77;
  BYTE b78;
  BYTE b79;
  BYTE b80;
  BYTE b81;
  BYTE b82;
  BYTE b83;
  BYTE b84;
}; 
ItemEx *pItem;

char *DecryptXorEnc(char *lpSrcBuf, int Size)
{
  BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };

  for (int i = 0; i < Size; ++i)
	lpSrcBuf[i] ^= XorKeys[i % 3];
 
  return lpSrcBuf;
}

size_t GetFileSize(void *pSrcBuf, size_t Size, size_t Count, FILE *fp)
{ 
  fseek(fp, 0 , SEEK_END);
  int ItemSz = ftell(fp);
  rewind(fp);
  size_t Result = fread(pSrcBuf, Count, Size, fp);
  return Result;
}

bool ReadItemBmd(char *pFileName)
{
  const int ITEM_TOTAL_LINE_SIZE = ITEM_LINE_SIZE << 13;

  pItem = new ItemEx();

  char *lpDstBuf = new char[ITEM_TOTAL_LINE_SIZE];
  char *lpSrcBuf = new char[ITEM_TOTAL_LINE_SIZE];
	
  FILE *fp = NULL;
  if ((fp = fopen(pFileName, "rb")) == NULL)
	return false;

  FILE *sp = NULL;
  if ((sp = fopen(".\\ItemDec.txt", "w")) == NULL)
	return false;

   GetFileSize(lpDstBuf, 1, ITEM_TOTAL_LINE_SIZE , fp);

  for (int i = 0; i < ITEM_TOTAL_LINE_SIZE  / ITEM_LINE_SIZE; ++i)
  {
	lpSrcBuf = DecryptXorEnc(&lpDstBuf[i * ITEM_LINE_SIZE], ITEM_LINE_SIZE);
	memcpy(pItem, &lpSrcBuf[0], ITEM_LINE_SIZE);
	fprintf(sp, "[%30s][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d][%3d]\n", 
	 pItem->ItemName, pItem->b31, pItem->b32, pItem->b33, pItem->b34, pItem->b35, pItem->b36, pItem->b37, pItem->b38, pItem->b39, pItem->b40, pItem->b41, pItem->b42, pItem->b43, pItem->b44, pItem->b45, pItem->b46, pItem->b47, pItem->b48, pItem->b49, pItem->b50,
	 pItem->b51, pItem->b52, pItem->b53, pItem->b54, pItem->b55, pItem->b56, pItem->b57, pItem->b58, pItem->b59, pItem->b60, pItem->b61, pItem->b62, pItem->b63, pItem->b64, pItem->b65, pItem->b66, pItem->b67, pItem->b68, pItem->b69, pItem->b70, pItem->b71, pItem->b72, 
	 pItem->b73, pItem->b74, pItem->b75, pItem->b76, pItem->b77, pItem->b78, pItem->b79, pItem->b80, pItem->b81, pItem->b82, pItem->b83, pItem->b84);
  }

  delete [] lpDstBuf, lpSrcBuf;
  lpDstBuf = lpSrcBuf = NULL;
  delete pItem;
  pItem = NULL;

  fclose(fp);
  fclose(sp);
  return true;
}

int main(void)
{
  if (!ReadItemBmd(".\\Item.bmd"))
  {
   MessageBoxA(NULL, "Item.bmd - File corrupted.", "Error", MB_ICONERROR);
   ::ExitProcess(0);
  }
  std::cout << "Press key!" << std::endl;
  std::cin.get(); return 0;
};

Skill.bmd.

Spoiler:
Code:
#include <iostream>

#include <stdio.h>
#include <conio.h>
#include <windows.h>

const int SKILL_LINE_SIZE = 80;
const int SKILL_TOTAL_LINE_SIZE = 600;

struct SkillEx
{
 char SkillName[32];
 WORD wLevel;	   // 34
 wORD wDamage;	 // 36
 WORD wReqMana;	// 38
 WORD wAG;	   // 40
 WORD wDistance;   // 42
 DWORD dwDelay;	// 46
 BYTE wMagic;	   // 47
 BYTE wLeader;	   // 48
 BYTE wResistance; // 49
 BYTE wType;	   // 50
 BYTE wUseType;	   // 51
 BYTE wBrand;	   // 52
 BYTE wCount;	   // 53
 BYTE wStatus1;	   // 54
 BYTE wStatus2;	   // 55
 BYTE wStatus3;	   // 56
 BYTE DW;	   // 57
 BYTE DK;	   // 58
 BYTE ELF;	   // 59
 BYTE MG;	   // 60
 BYTE DL;	   // 61
 BYTE SUM;	   // 62
 BYTE IconNumber;  // 63
 BYTE SkillType;   // 64
 BYTE Unkw1;	   // 65
 BYTE Unkw2;	   // 66
 BYTE Unkw3;	   // 67
 BYTE Unkw4;	   // 68
 BYTE Unkw5;	   // 69
 BYTE Unkw6;	   // 70
 BYTE Unkw7;	   // 71
 BYTE Unkw8;	   // 72
 BYTE Unkw9;	   // 73
 BYTE Unkw10;	  // 74
 BYTE Unkw11;	  // 75
 BYTE Unkw12;	  // 76
 BYTE Unkw13;	  // 77
 BYTE Unkw14;	  // 78
 BYTE Unkw15;	  // 79
 BYTE Unkw16;	  // 80
};
SkillEx *pSkill; // 80

char *DecryptXorEnc(char *lpSrcBuf, int Size)
{
  BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };

  for (int i = 0; i < Size; ++i)
   lpSrcBuf[i] ^= XorKeys[i % 3];
 
  return lpSrcBuf;
}

size_t GetFileSize(void *pSrcBuf, size_t Size, size_t Count, FILE *fp)
{ 
  fseek(fp, 0 , SEEK_END);
  int ItemSz = ftell(fp);
  rewind(fp);
  size_t Result = fread(pSrcBuf, Count, Size, fp);
  return Result;
}

bool ReadSkillBmd(char *pFileName)
{
  pSkill = new SkillEx();

  char *lpDstBuf = new char[SKILL_TOTAL_LINE_SIZE * SKILL_LINE_SIZE];
  char *lpSrcBuf = new char[SKILL_TOTAL_LINE_SIZE * SKILL_LINE_SIZE];
	
  FILE *fp = NULL;
  if ((fp = fopen(pFileName, "rb")) == NULL)
   return false;

  FILE *sp = NULL;
  if ((sp = fopen(".\\SkillDec.txt", "w")) == NULL)
   return false;

  GetFileSize(lpDstBuf, 1, SKILL_TOTAL_LINE_SIZE * SKILL_LINE_SIZE, fp);

  for (int i = 0; i < SKILL_TOTAL_LINE_SIZE; ++i)
  {
   lpSrcBuf = DecryptXorEnc(&lpDstBuf[i * SKILL_LINE_SIZE], SKILL_LINE_SIZE);
   memcpy(pSkill, &lpSrcBuf[0], SKILL_LINE_SIZE);
  fprintf(sp, "[%s][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d  [%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d]", 
  pSkill->SkillName, pSkill->wLevel, pSkill->wDamage, pSkill->wReqMana, pSkill->wAG, pSkill->wDistance, pSkill->dwDelay, pSkill->wMagic, pSkill->wLeader, pSkill->wResistance,
  pSkill->wType, pSkill->wUseType, pSkill->wBrand, pSkill->wCount, pSkill->wStatus1, pSkill->Status2, pSkill->Status3, pSkill->DW, pSkill->DK, pSkill->ELF, pSkill->MG, pSkill->DL, pSkill->SUM
  pSkill->IconNumber, pSkill->SkillType, pSkill->Unkw1, pSkill->Unkw2, pSkill->Unkw3, pSkill->Unkw4, pSkill->Unkw5, pSkill->Unkw6, pSkill->Unkw7, pSkill->Unkw8, pSkill->Unkw9, pSkill->Unkw10, 
  pSkill->Unkw11, pSkill->Unkw12, pSkill->Unkw13, pSkill->Unkw14, pSkill->Unkw15, pSkill->Unkw16);
  }

  delete [] lpDstBuf, lpSrcBuf;
  lpDstBuf = lpSrcBuf = NULL;
  delete pSkill;
  pSkill = NULL;

  fclose(fp);
  fclose(sp);
  return true;
}

int main(void)
{
  if (!ReadSkillBmd(".\\Skill.bmd"))
  {
   MessageBoxA(NULL, "Skill.bmd - File corrupted.", "Error", MB_ICONERROR);
   ::ExitProcess(0);
  }
  std::cout << "Press key!" << std::endl;
  std::cin.get(); return 0;
};

Gate.bmd

Spoiler:
Code:
#include <iostream>

#include <stdio.h>
#include <conio.h>
#include <windows.h>

const int GATE_LINE_SIZE = 14;
const int GATE_TOTAL_LINE_SIZE = 512

struct GateEx
{
  BYTE Flag; 
  BYTE Map; 
  BYTE X1;
  BYTE X2;
  BYTE Y1;
  BYTE Y2;
  WORD wGateNumber;
  BYTE Dir;
  BYTE bBattleZone;
  WORD wLevel; // Походу требуемый уровень для прохода
  WORD wBattleZoneLvlReq; 
}; 
GateEx *pGate; // 14

char *DecryptXorEnc(char *lpSrcBuf, int Size)
{
  BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };
  for (int i = 0; i < Size; ++i)
	lpSrcBuf[i] ^= XorKeys[i % 3];
  return lpSrcBuf;
}

size_t GetFileSize(void *pSrcBuf, size_t Size, size_t Count, FILE *fp)
{
  fseek(fp, 0 , SEEK_END);
  int ItemSz = ftell(fp);
  rewind(fp);
  size_t Result = fread(pSrcBuf, Count, Size, fp);
  return Result;
}

bool ReadGateBmd(char *pFileName)
{
  pGate = new GateEx();

  char *lpDstBuf = new char[GATE_LINE_SIZE * GATE_TOTAL_LINE_SIZE];
  char *lpSrcBuf = new char[GATE_LINE_SIZE * GATE_TOTAL_LINE_SIZE];

  FILE *fp = NULL;
  if ((fp = fopen(pFileName, "rb")) == NULL)
	return false;

  FILE *sp = NULL;
  if ((sp = fopen(".\\GateDec.txt", "w")) == NULL)
	return false;

  GetFileSize(lpDstBuf, 1, GATE_LINE_SIZE * GATE_TOTAL_LINE_SIZE, fp);

  for (int i = 0; i < GATE_TOTAL_LINE_SIZE; ++i)
  {
	lpSrcBuf = DecryptXorEnc(&lpDstBuf[GATE_LINE_SIZE * i], GATE_LINE_SIZE);
	memcpy(pGate, &lpSrcBuf[0], GATE_LINE_SIZE);
	fprintf(sp, "[%d][%d][%d][%d][%d][%d][%d][%d][%d][%d][%d]\n", 
	pGate->Flag, pGate->Map, pGate->X1, pGate->X2, pGate->Y1, pGate->Y2, pGate->wGateNumber, pGate->Dir, pGate->bBattleZone, pGate->wLevel, pGate->wBattleZoneLvlReq);
  }

  delete [] lpDstBuf, lpSrcBuf;
  lpDstBuf = lpSrcBuf = NULL;
  delete pGate;
  pGate = NULL;

  fclose(fp);
  fclose(sp);
  return true;
}

int main(void)
{
  if (!ReadGateBmd(".\\Gate.bmd"))
  {
   MessageBoxA(NULL, "Gate.bmd - File corrupted.", "Error", MB_ICONERROR);
   ::ExitProcess(0);
  }
  std::cout << "Press key!" << std::endl;
  std::cin.get(); return 0;
};

Filter.bmd

Spoiler:
Code:
#include <iostream>

#include <stdio.h>
#include <conio.h>
#include <windows.h>

const int FILTER_LINE_SIZE = 20;
const int FILTER_TOTAL_LINE_SIZE = 1000;

struct FilterEx
{
 char FilterText[20];
};
FilterEx *pFilter; 

char *DecryptXorEnc(char *lpSrcBuf, int Size)
{
 BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };
 for (int i = 0; i < Size; ++i)
  lpSrcBuf[i] ^= XorKeys[i % 3];
 return lpSrcBuf;
}

size_t GetFileSize(void *pSrcBuf, size_t Size, size_t Count, FILE *fp)
{ 
 fseek(fp, 0 , SEEK_END);
 int ItemSz = ftell(fp);
 rewind(fp);
 size_t Result = fread(pSrcBuf, Count, Size, fp);
 return Result;
}

bool ReadFilterBmd(char *pFileName)
{
 pFilter = new FilterEx();

 char *lpDstBuf = new char[FILTER_TOTAL_LINE_SIZE * FILTER_LINE_SIZE];
 char *lpSrcBuf = new char[FILTER_TOTAL_LINE_SIZE * FILTER_LINE_SIZE];
	
 FILE *fp = NULL;
 if ((fp = fopen(pFileName, "rb")) == NULL)
  return false;

 FILE *sp = NULL;
 if ((sp = fopen(".\\FilterDec.txt", "w")) == NULL)
  return false;

  GetFileSize(lpDstBuf, 1, FILTER_TOTAL_LINE_SIZE * FILTER_LINE_SIZE, fp);

  for (int i = 0; i < FILTER_TOTAL_LINE_SIZE; ++i)
  {
   lpSrcBuf = DecryptXorEnc(&lpDstBuf[i * FILTER_LINE_SIZE], FILTER_LINE_SIZE);
   memcpy(pFilter, &lpSrcBuf[0], FILTER_LINE_SIZE);
   fprintf(sp, "[%s]\n", pFilter->FilterText);
  }

  delete [] lpDstBuf, lpSrcBuf;
  lpDstBuf = lpSrcBuf = NULL;
  delete pFilter;
  pFilter = NULL;

  fclose(fp);
  fclose(sp);
  return true;
}

int main(void)
{
  if (!ReadFilterBmd(".\\Filter.bmd"))
  {
   MessageBoxA(NULL, "Filter.bmd - File corrupted.", "Error", MB_ICONERROR);
   ::ExitProcess(0);
  }
  std::cout << "Press key!" << std::endl;
  std::cin.get(); return 0;
};

FilterName.bmd

Spoiler:
Code:
#include <iostream>

#include <stdio.h>
#include <conio.h>
#include <windows.h>

const int FILTERNAME_LINE_SIZE = 20;
const int FILTERNAME_TOTAL_LINE_SIZE = 500;

struct FilterNameEx
{
 char FilterNameText[20];
};
FilterNameEx *pFilterName; 

char *DecryptXorEnc(char *lpSrcBuf, int Size)
{
 BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };
 for (int i = 0; i < Size; ++i)
  lpSrcBuf[i] ^= XorKeys[i % 3];
 return lpSrcBuf;
}

size_t GetFileSize(void *pSrcBuf, size_t Size, size_t Count, FILE *fp)
{ 
 fseek(fp, 0 , SEEK_END);
 int ItemSz = ftell(fp);
 rewind(fp);
 size_t Result = fread(pSrcBuf, Count, Size, fp);
 return Result;
}

bool ReadFilterNameBmd(char *pFileName)
{
 pFilterName = new FilterNameEx();

 char *lpDstBuf = new char[FILTERNAME_TOTAL_LINE_SIZE * FILTERNAME_LINE_SIZE];
 char *lpSrcBuf = new char[FILTERNAME_TOTAL_LINE_SIZE * FILTERNAME_LINE_SIZE];
	
 FILE *fp = NULL;
 if ((fp = fopen(pFileName, "rb")) == NULL)
  return false;

 FILE *sp = NULL;
 if ((sp = fopen(".\\FilterNameDec.txt", "w")) == NULL)
  return false;

  GetFileSize(lpDstBuf, 1, FILTERNAME_TOTAL_LINE_SIZE * FILTERNAME_LINE_SIZE, fp);

  for (int i = 0; i < FILTERNAME_TOTAL_LINE_SIZE; ++i)
  {
   lpSrcBuf = DecryptXorEnc(&lpDstBuf[i * FILTERNAME_LINE_SIZE], FILTERNAME_LINE_SIZE);
   memcpy(pFilterName, &lpSrcBuf[0], FILTERNAME_LINE_SIZE);
   fprintf(sp, "[%s]\n", pFilterName->FilterNameText);
  }

  delete [] lpDstBuf, lpSrcBuf;
  lpDstBuf = lpSrcBuf = NULL;
  delete pFilterName;
  pFilterName = NULL;

  fclose(fp);
  fclose(sp);
  return true;
}

int main(void)
{
 if (!ReadFilterNameBmd(".\\FilterName.bmd"))
 {
  MessageBoxA(NULL, "FilterName.bmd - File corrupted.", "Error", MB_ICONERROR);
  ::ExitProcess(0);
 }
 std::cout << "Press key!" << std::endl;
 std::cin.get(); return 0;
};

Dialog.bmd

Spoiler:
Code:
#include <iostream>

#include <stdio.h>
#include <conio.h>
#include <windows.h>

const int DIALOG_LINE_SIZE = 1024;
const int DIALOG_TOTAL_LINES = 200;

struct DialogEx
{
 char DialogText[1024];
};
DialogEx *pDialog; 

char *DecryptXorEnc(char *lpSrcBuf, int Size)
{
 BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };

 for (int i = 0; i < Size; ++i)
  lpSrcBuf[i] ^= XorKeys[i % 3];

 return lpSrcBuf;
}

size_t GetFileSize(char *pSrcBuf, size_t Size, size_t Count, FILE *fp)
{ 
 size_t Result = fread(pSrcBuf, Size, Count, fp);
 return Result;
}

bool ReadDialogBmd(char *pFileName)
{
 pDialog = new DialogEx();

 FILE *fp;
 if ((fp = fopen(pFileName, "rb")) == NULL)
  return false;

 FILE *sp;
 if ((sp = fopen(".\\DialogDec.txt", "w")) == NULL)
  return false;

 char *lpDstBuf = new char [DIALOG_LINE_SIZE ];	

 for (int i = 0; i < DIALOG_TOTAL_LINES; ++i)
 {		
  GetFileSize(lpDstBuf, DIALOG_LINE_SIZE, 1, fp);
  DecryptXorEnc(&lpDstBuf[0], DIALOG_LINE_SIZE);
  memcpy(pDialog, &lpDstBuf[0], DIALOG_LINE_SIZE);
  fprintf(sp, "[%s]\n", pDialog->DialogText);
 }

 delete pDialog;
 pDialog = NULL;

 delete [] lpDstBuf;
 lpDstBuf = NULL;

 fclose(fp);
 fclose(sp);

 return true;
}

int main(void)
{
 if (!ReadDialogBmd(".\\Dialog.bmd"))
 {
  MessageBoxA(NULL, "Dialog.bmd - File corrupted.", "Error", MB_ICONERROR);
  ::ExitProcess(0);
 }
 std::cout << "Press key!" << std::endl;
 std::cin.get(); return 0;
};

Text.bmd

Spoiler:
Code:
#include <iostream>
#include <vector>
#include <windows.h>
#include <fstream>
 
#define FILE_PATH ".\\Text.bmd"

enum PROGRAM { SUCCESS = 0, WARNING = 1 };

struct TextEx
{
 char *Text;
};
TextEx *pText;

size_t GetFileSize(void *lpSrcBuf, size_t Size, size_t Count, FILE *fp)
{
 size_t result = fread(lpSrcBuf, Size, Count, fp);
 return result;
}

void DecryptXorEnc(char *lpSrcBuf, int Size)
{
 BYTE XorKeys[3] = { 0xFC, 0xCF, 0xAB };

 for (int i = 0; i < Size; ++i)
  lpSrcBuf[i] ^= XorKeys[i % 3];
}

bool ReadTextBmd(char pFileName[], int Size)
{
 FILE *fp, *sp;

 if ((fp = fopen(pFileName, "rb")) == NULL) return false;
 if ((sp = fopen(".\\TextDec.txt", "w")) == NULL) return false;

 char *lpSrcBuf	= (char*)malloc(strlen(pFileName) + 1);
 strcpy(&lpSrcBuf[0], pFileName);
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s