EMO Style ForumPro - Hos Geldiniz
Giriş yap

Şifremi unuttum

Toplam 202 kayıtlı kullanıcımız var
Son kaydolan kullanıcımız: AnthonyFurey3

Kullanıcılarımız toplam 1186 mesaj attılar bunda 862 konu
 Üye Listesi

Sonuç :

Rechercher çıkıntı araştırma

RSS akısı


Kimler hatta?
Toplam 4 kullanıcı online :: 0 Kayıtlı, 0 Gizli ve 4 Misafir


[ Bütün listeye bak ]

Sitede bugüne kadar en çok 92 kişi Paz Ağus. 28, 2016 6:58 am tarihinde online oldu.
En son konular
» İnternetten Para Kazandıran Oyun ! Ödeme Alt Limiti Yok ! DEV KONU
Cuma Ağus. 29, 2014 8:33 am tarafından Hello EMO

» goldenchase.net maden yaparak para kazanma
Cuma Ağus. 29, 2014 8:18 am tarafından Hello EMO

» etichal hacker görsel egitim seti
Çarş. Ağus. 06, 2014 4:57 am tarafından Hello EMO

» KO TBL Source C#
Ptsi Ara. 09, 2013 6:36 am tarafından Hello EMO

» x86 Registers
C.tesi Ağus. 24, 2013 5:02 am tarafından Hello EMO

» [Tutorial] Pegando Address, Pointers de WYD
Çarş. Tem. 10, 2013 7:25 am tarafından Hello EMO

» [Tutorial] Pegando Address, Pointers de CS Metodo²
Çarş. Tem. 10, 2013 7:23 am tarafından Hello EMO

» [Tutorial] Aprendendo basico deASM OLLYDBG
Çarş. Tem. 10, 2013 7:22 am tarafından Hello EMO

» Basic C# DLL injector
Ptsi Tem. 08, 2013 7:48 am tarafından Hello EMO


(C++) Quick guide on making a Knight Online Dupe Scanner

Önceki başlık Sonraki başlık Aşağa gitmek

(C++) Quick guide on making a Knight Online Dupe Scanner

Mesaj tarafından Hello EMO Bir Çarş. Şub. 23, 2011 8:43 am

[quote name='BlaDe' timestamp='1296420424' post='165']
As my old guide was lost, I thought I'd put a new one together. It may/may not be a working sample, it's extract of code I used in FraDe back in 1298 or so and the rest I have written directly into the browser...Either way it's a great start for anyone looking to start on various KO server file projects.

To begin. You will require a set of definitions to work from, these are rather old and I can't find my full struct, so you may find better ones being posted around here at some point but these should work for this purpose!


#define MAX_USER_ID_SIZE   20
#define MAX_ACC_ID_SIZE      38
#define MAX_USER      1500

#define SLOT_MAX      14
#define HAVE_MAX      28   
#define ITEMCOUNT_MAX      9999
#define WAREHOUSE_MAX      196   

   int      nNum;   
   short   sDuration;   
   short   sCount;      
   __int64   nSerialNum;   
   char cPadding[8];
   int   nNum;   
   short   sDuration;   
   short   sCount;      
   __int64   nSerialNum;   

struct _USER_DATA
   char   m_id[MAX_USER_ID_SIZE+1];         
   char   m_Accountid[MAX_ACC_ID_SIZE+1];      
   DWORD   m_bZone;   

   float   m_curx;   
   float   m_cury;      
   float   m_curz;                     

    BYTE   m_bNation;
   BYTE   m_bRace;
   short   m_sClass;
   BYTE   m_bHairColor;
   BYTE   m_bRank;
   BYTE   m_bTitle;
   BYTE   m_bLevel;
   int   m_iExp;
   int   m_iLoyalty;
   BYTE   m_bFace;
   BYTE   m_bCity;
   short   m_bKnights;
   short   m_sClan;
   short  m_sUnknown;
   BYTE   m_bFame;

   byte m_unknown2;
   byte m_Hits;
   byte m_Mana;
   byte m_SP;
   byte m_STR;
   byte m_HP;
   byte m_DEX;
   byte m_INT;
   byte m_MP;
   byte m_Authority;
   byte m_Points;
   byte m_unknown3;

   DWORD m_Gold;
   signed short m_Bind;
   int m_Bank;

   char Garbage[39]; // skill/stat stuff etc
   //_ITEM_DATA m_sItemArray[HAVE_MAX+SLOT_MAX]; // 42*8 bytes
   INN_ITEM_DATA m_sWarehouseArray[WAREHOUSE_MAX];   //196*8 bytes

   BYTE   m_bLogout;
   BYTE   m_bWarehouse;
   DWORD   m_dwTime;   

That is for mapping against the memory mapped file (sometimes referred to as shared memory access) and we will cast a block of memory to that structure so we don't have to loop by lots of mathematical offsets, it generally makes the code cleaner to work with.

Some internal declarations may look something like this:



   typedef std::vector<_USER_DATA*> UserDataArray;
   extern UserDataArray currentUsers;
   HANDLE m_hUsersMutex;
   HANDLE m_hMMFile;
   char* m_lpMMFile;

   void myPopulateFunction()

So first of all, let's connect to the file and build up our local array. (You'll probably want to place this in your main, or equivalent.)

Note: I'm not going to incorporate lots of error handling etc in this guide, you will need to do that yourself.


   m_hUsersMutex = CreateMutex( NULL, FALSE, NULL );
   m_hMMFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, TRUE, MMF_TARGET);

   if(m_hMMFile == NULL)

   m_lpMMFile = (char *)MapViewOfFile (m_hMMFile, FILE_MAP_WRITE, 0, 0, 0);

   if (!m_lpMMFile)


Okay, so this will open up the shared memory files that Knight Online uses to access the user data from all the various applications (aujard and ebenezer for example) and map it so we can access its data from our application. Next up, loading all of the users from the memory block and casting it to a nice struct which was defined above!


void myPopulateFunction() {
   WaitForSingleObject( m_hUsersMutex, INFINITE );

   // This is where we'll do our stuff.


That's a rough outline for our function, we use a mutex to prevent any of our other functions accessing the array while it's being written to which could cause memory exceptions and such. So let's load our users now.


void myPopulateFunction() {
   WaitForSingleObject( m_hUsersMutex, INFINITE );

   _USER_DATA* pUser = NULL;

   for (int i=0; i < MAX_USER; i++) {
      pUser = (_USER_DATA*)(m_lpMMFile+(i*8000));


Because the struct above isn't entirely complete, when looping each user we can't use sizeof(_USER_DATA) as we ideally should - as such it's hard coded as 8000 bytes, this may need maintaining in future versions, or fix the struct up!

This will build an array of pointers to each user - so all data is always accurate without you needing to re-populate. This has its merits and cons, so in some situations we need to create a static array too which we'll do next in the dupescanner example.

So next, let's just take a look at iterating through the array so we can actually use it!


   std::vector<_USER_DATA*>::iterator iter;
   for (iter = currentUsers.begin(); iter != currentUsers.end(); iter++) {
      // our magic

Really simple stuff there, you can then access the properties of each user directly. Beware of the null structs (as again, these are simply pointers to a block of memory) so do a check for something like (*iter)->m_id having a positive length.

An example of applying the above code could be to find a pointer to a struct from a given username, how about this:


_USER_DATA* getStructByUser(const char *user) {
   WaitForSingleObject( m_hUsersMutex, INFINITE );
   std::vector<_USER_DATA*>::iterator iter;
   for (iter = currentUsers.begin(); iter != currentUsers.end(); iter++) {
      if (!_strnicmp(user, (*iter)->m_id, MAX_USER_ID_SIZE)
         return *iter

   return FALSE;

There are so many more potential applications to this - for example a decent speed hacking detector, zone scanning for if users are stuck in the war zone, or bugs with invading and whatever, and of course the biggie, dupe scanning.

Let's create a quick draft on how you may achieve something like this!

You'll probably want to create it in a separate thread, so add something like this to our definitions


struct threadStruct
   HANDLE* hMutex;
   UserDataArray* curUsers;

Then finally, some code!


unsigned __stdcall DupeScanThread(LPVOID lp)   
   threadStruct* pStruct = (threadStruct*)lp;

   UserDataArray* pUsers = (UserDataArray*)pStruct->curUsers;
   UserDataArray pTemp;

   map<__int64, _USER_DATA*> userMap;

   WaitForSingleObject(pStruct->hMutex, INFINITE );
   pTemp.assign(pUsers->begin(), pUsers->end());

   for (iter = pTemp.begin(); iter != pTemp.end(); iter++) {
      _USER_DATA* pUser = *iter;
      if (!strlen(pUser->m_id)) continue;

      for (int i=0; i<HAVE_MAX+SLOT_MAX;i++) {
         if (pUser->m_sItemArray[i].nSerialNum > 0 && pUser->m_sItemArray[i].nNum > 0) {   
            if (!userMap.insert(make_pair(pUser->m_sItemArray[i].nSerialNum, *pUser)).second) {
               _USER_DATA* otherDuper = userMap.find(pUser->m_sItemArray[i].nSerialNum)->second;
               // Do some magic


You may notice that I only ran it once in the above example, you may want to add an extra parameter for bEnabled, then add a while (bEnabled) { sleep(); pTemp.clear(), re fill, the interation, etc } to run it constantly!
I haven't gone into the full depths of utilising the mapped file to send packets (for disconnecting and such) in this guide it's focussed KNIGHT_DB only, but I may cover that at some point in the future.

To initialise the thread, it'll be something like this:


threadStruct params;
params.hMutex = &m_hUsersMutex;
params.curUsers = ¤tUsers;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, DupeScanThread, ¶ms, 0, NULL);

Please forgive any mistakes I've made, I actually wrote most of this code directly into the browser.

Hello Kitty

Hello EMO
EMO Team
EMO Team

Cinsiyet : Erkek
Burçlar : Yay
Mesaj Sayısı : 935
Puan : 241193
Rep Puanı : 18
Doğum tarihi : 28/11/89
Kayıt tarihi : 21/07/09
Yaş : 27
Nerden : EMO WorlD
İş/Hobiler : RCE Student / Game Hacking / Learn Beginner C#,C++,Delphi
Lakap : EMO

Kullanıcı profilini gör http://emostyle.myforumpro.com

Sayfa başına dön Aşağa gitmek

Önceki başlık Sonraki başlık Sayfa başına dön

- Similar topics

Bu forumun müsaadesi var:
Bu forumdaki mesajlara cevap veremezsiniz