• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            聚星亭

            吾笨笨且懶散兮 急須改之而奮進
            posts - 74, comments - 166, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理
                【前言】
                    夜里失眠,到這個論壇上泡,發現這個編程版塊不是很正規,因為我認為的好的編程版塊應該是以討論分享及解決具體問題而存在的,而不是想咱論壇這樣:
            救助的問題不明確,分享就是單純的分享源碼,分享XX成品之類……

                【廢話】
                      前幾天研究外掛了,就我這點破水平,脫機啊,封包掛啊之類的與我無緣了,只能做做內掛,滿足一下自己的虛榮心……
                 這里大概的給大家分享一下做內掛編程方面的知識,高手飄過,跟我一樣菜的朋友多多提出您的寶貴意見,相互學習、共勉!!!
                 當然了,也希望這篇文章能騙個精華之類的東東,作為我炫耀的資本~~~~
                 內掛,其實不難的,這里主要分享遠程線程注入相關的東西,至于其它什么游戲找CALL,功能CALL調用相關的東西,可以參考一下我寫的:
                 賺取權限第三貼,一個有意思的keygenMe的逆向分析
                      其實道理都是相同的,當然,如果您非常想要了解相關的東西,請參考別人大牛寫的文章,這里不做詳細討論。

                 【基礎】
                  我理解的遠程線程注入,包括注入代碼,注入DLL分為這兩種(如果有不對的地方希望指正,謝謝),注入DLL就不多廢話了,就是把DLL及所在目錄的名字一些通過寫內存的API寫到目標進程中,我今天主要討論的是向目標進程寫代碼,是獲取目標進程的句柄的方法有很多的,比如創建進程鏡像,然后遍歷進程,再如通過遍歷窗口標題,類名之類得到窗口句柄,然后在由窗口句柄得到進程的句柄,這里只舉最常用到的通過窗口名的方法,至于遍歷進程的方法有很多的,您可以百度一下就能找到……
            void CZHGameDlg::OnShuaxin() 
            {
                    
            //載入游戲
                    DWORD dwZHThreadId;
                    DWORD dwZHProcessId;
                    HWND hZHWnd;
                    DWORD BASE;
                    
            char tmpName[65];
                    
            int i = 0;
                    CString sClassName
            = "";


                    hZHWnd 
            = ::FindWindow("縱橫時空",NULL);
                    UpdateData(TRUE);
                    m_nChioceGM.ResetContent(); 
                    
            if(hZHWnd != NULL)
                    {
                            
            while(hZHWnd > 0)
                            {
                                    
            if(i >=5)
                                    {
                                            ::AfxMessageBox(
            "因掛機效率考慮,本掛最多可以控制5個角色!請關閉一些角色然后點刷新按鈕!");
                                            
            break;
                                    }
                                    
            int hFunc=GetClassName(hZHWnd,sClassName.GetBuffer(0),2000);
                                    
            if(hFunc != 0 && 0 <= sClassName.Find("縱橫時空"))
                                    {
                                            
            if( dwZHThreadId = ::GetWindowThreadProcessId(hZHWnd, &dwZHProcessId))
                                            {
                                                    
            try
                                                    {
                                                            m_hZHProcess 
            = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwZHProcessId+1);
                                                            
            if(m_hZHProcess != NULL) 
                                                            {
                                                                    ReadProcessMemory(m_hZHProcess,(LPVOID)ZH_BASE_ADDR,
            &BASE,4,NULL); 
                                                                    ReadProcessMemory(m_hZHProcess,(LPVOID)(BASE
            +0xAC),tmpName,20,NULL); 

                                                                    ProcName[i].Name 
            = tmpName;
                                                                    ProcName[i].hZHhwnd 
            = hZHWnd;
                                                                    ProcName[i].hZHProcess 
            = m_hZHProcess;
                                                                    
            if0> m_nChioceGM.FindStringExact(0,ProcName[i].Name))
                                                                    m_nChioceGM.AddString(ProcName[i].Name);

                                                                    SetDlgItemText(IDC_TISHI,
            "提示: 遍歷游戲角色完畢,請選擇游戲角色");

                                                                    i
            ++;
                                                                    UpdateData(FALSE);
                                                            }
                                                      }
            catch()
                                                      {
                                                            ::AfxMessageBox(
            "出現未知錯誤");
                                                    } 
                                            }
                                    }

                                    hZHWnd 
            = ::GetNextWindow(hZHWnd,GW_HWNDNEXT); 
                            } 
                    }
                    
            else
                    {
                            SetDlgItemText(IDC_TISHI,
            "提示: 沒有找到游戲窗口,請確認游戲是否已經開啟");
                    }
            }

            這樣我們就可以得到同一個游戲的所有窗口句柄、進程句柄,游戲角色名等信息(這里只以縱橫時空這個游戲來說,由于不同的游戲,游戲數據的存儲用的數據結構各不相同,所以,這個取角色名的位置不能通用!)如果你有其它的方法,歡迎跟帖子分享!


                  【內容一:簡單的代碼執行】
                   到這里,我們已經得到目標窗口的句柄了,然后接下來就是調用游戲中的函數,讓游戲去執行它,以達到我們的通過程序控制的目的!
                  比如,我先要讓我們的程序能夠控制游戲,比如讓我們程序控制的角色簡單的跳一下。假設我們通過分析游戲的代碼,找到,跳,這個動作的代碼如下:
            //--------->跳<---------//
            DWORD _stdcall JumpA()
            {
                    DWORD RealAddress,Addr;
                    Sell_STR SellParam;

                    RealAddress 
            = 0x00409C80//真正CALL地址
                    Addr = 0x004336F0//加密CALL地址

                    _asm
                    {
                            push 
            0
                            mov eax, dword ptr [
            0x00833C5C//游戲基址
                            add eax, 108
                            push eax
                            lea ecx,SellParam
                            call Addr
                            push eax
                            MOV ecx, 
            0x0084B908
                            call RealAddress
                    }
                    
            return 0;
            }

            只要我們能讓游戲順利的執行我們的上述代碼,我們就可以通過傳入不同的參數,來達到拾取物品的目的!
                     怎么樣來讓游戲執行這個代碼呢?
                     游戲的進程跟我們自己的進程是兩個獨立的實例,自然的,游戲不會跑到我們的進程空間內來執行我們程序的代碼,否則Windows就亂套了~~~,我們要做的,就只有兩步!
                     第一步  :  把要讓游戲執行的代碼寫入游戲的進程空間內!
                     第二步 : 給游戲進程創建一個線程,讓它執行上述的代碼!

                    其實要完成上述的兩步不難的,寫目標進程的API函數是:WriteProcessMemory  ,具體的定義如下:
            BOOL WriteProcessMemory(
                            HANDLE hProcess, 
            // handle to process whose memory is written to
                            LPVOID lpBaseAddress,
                            
            // address to start writing to
                            LPVOID lpBuffer, // pointer to buffer to write data to
                            DWORD nSize, // number of bytes to write
                            LPDWORD lpNumberOfBytesWritten 
                            
            // actual number of bytes written
            );
            至于在目標進程創建個線程的API及定義如下:
            HANDLE CreateRemoteThread(
                            HANDLE hProcess, 
            // handle to process to create thread in
                            LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes
                            DWORD dwStackSize, // initial thread stack size, in bytes
                            LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function
                            LPVOID lpParameter, // argument for new thread
                            DWORD dwCreationFlags, // creation flags
                            LPDWORD lpThreadId // pointer to returned thread identifier
            );
            好了,把我寫的一個遠程線程注入代碼的函數貼一下:
            void    InjectToProcess(DWORD (*FunName)())
            {
                    HANDLE TmpHandle;
                    DWORD dwThreadId;
                    DWORD dwProcessId;

                    CString sClassName
            = "";

                    m_hPwnd 
            = ::FindWindow("TForm1","游戲找CALL練習實例one");//得到窗口句柄

                    
            if(m_hPwnd == NULL)
                    {
                            MessageBox(
            "沒有找到主程序,請先運行主程序");
                    }

                    
            int hFunc=GetClassName(m_hPwnd,sClassName.GetBuffer(0),2000);
                    
            if(hFunc != 0 && 0 <= sClassName.Find("TForm1"))
                    {
                            
            if( dwThreadId = ::GetWindowThreadProcessId(m_hPwnd, &dwProcessId))
                            {
                                    m_hProcess 
            = ::OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessId);
                                    
            if(m_hProcess != NULL) 
                                    {
                                            
            //在目標進程建立內存空間 
                                            LPVOID ThreadAdd = ::VirtualAllocEx(m_hProcess, NULL,0x1024, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                                            ::WriteProcessMemory(m_hProcess,ThreadAdd ,FunName,
            0x1024,NULL); 
                                            TmpHandle 
            = CreateRemoteThread(m_hProcess, 
                                                                            NULL, 
            0, (LPTHREAD_START_ROUTINE)ThreadAdd, NULL, 
                                                                            
            0, NULL);//獲得注入后過程的句柄ID 

                                            
            if(WaitForSingleObject(TmpHandle,INFINITE) != WAIT_OBJECT_0)
                                            {
                                                    CString StrTmp;
                                                    StrTmp.Format(
            "%d",GetLastError());
                                                    MessageBox(StrTmp);
                                            }
                                            CloseHandle(TmpHandle);
                                            CloseHandle(m_hProcess);
                                            VirtualFreeEx(m_hProcess,ThreadAdd,
            0x1024,MEM_RELEASE);
                                    }
                            }
                    }
            }

            這樣,我們只要在函數里調用:InjectToProcess(JumpA)
            就可以搞定了!


                  【內容一:關于參數的傳遞】

                   其實,絕大多數游戲里的函數都是帶有參數的,遠程線程里參數的傳遞其實也不難的,直接舉個例子吧,希望對卡在這里的朋友有所幫助!
                  這里舉自動的拾取物品的例子,比如我們通過對游戲的分析,找到游戲拾取物品的代碼如下:
            //--------->撿取物品<---------//_OK
            void _stdcall JianWuA(PP1_STR P)
            {
                    DWORD SendAddr 
            = ZH_CALL_SEND;
                    DWORD SendEcx 
            = ZH_CALL_ECX;
                    DWORD Addr 
            = ZH_CALL_SHIQU;

                    DWORD WuPos;
                    DWORD XiangZiID;
                    Sell_STR SellParam;

                    DWORD Mubiao 
            = ZH_SQMUBIAO_ADDR;
                    WuPos 
            = P->Param1;
                    XiangZiID 
            = P->Param2;

                    _asm
                    {
                             push WuPos 
            //在物品欄的位置
                            push XiangZiID //要拾取的物品的ID
                            lea ecx,SellParam
                            Call Addr 
            //簡單的封包加密
                            push eax
                            MOV ecx, SendEcx
                            call SendAddr 
            //發包CALL
                            MOV BYTE PTR [Mubiao],0
                    }
            }

            這里需要的參數有兩個,一個是地上箱子的ID,一個是箱子中物品的位置,這里的遠程注入的函數當然也不像上一個函數那么簡單了,我改成了下面的樣子:

                  初始化部分:
            void CInjectCall::InitPorcess(HANDLE _hProcess)
            {
                m_hProcess 
            = _hProcess;
                
            if(m_hProcess != NULL)  
                {
                    
            //在目標進程中為函數名創建空間
                    ThreadAdd  = ::VirtualAllocEx(m_hProcess, NULL,0x128, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                    
            //在目標進程中為函數名創建空間
                    ParamAddr  = ::VirtualAllocEx(m_hProcess, NULL,0x128, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                    JiNengAddr  
            = ::VirtualAllocEx(m_hProcess, NULL,0x128, MEM_COMMIT,PAGE_EXECUTE_READWRITE);
                }
            }

                  注入部分:
            void CInjectCall::InjectFunc(LPVOID pFun, DWORD *Param, DWORD ParamSize)
            {
                    HANDLE TmpHandle;
                    DWORD lpNumberOfBytes;
                    
            if(m_hProcess != NULL) 
                    {
                            
            // ---- 寫入函數地址
                    ::WriteProcessMemory(m_hProcess, ThreadAdd, pFun, 0x128&lpNumberOfBytes); 
                            
            // ---- 寫入參數地址
                    ::WriteProcessMemory(m_hProcess, ParamAddr, Param, ParamSize, &lpNumberOfBytes);

                            TmpHandle 
            = ::CreateRemoteThread(m_hProcess, 
                                                            NULL, 
            0, (LPTHREAD_START_ROUTINE)ThreadAdd,
                                                            ParamAddr, 
            //有參數就寫參數,無參數就為NULL
                                                            0&lpNumberOfBytes);//獲得注入后過程的句柄ID 

                           ::WaitForSingleObject(TmpHandle,INFINITE);

                            ::CloseHandle(TmpHandle);
                    }
            }
                 內存釋放部分:
            void CInjectCall::TheEndPorcess()
            {
                
            if(m_hProcess != NULL)  
                {
                    ::VirtualFreeEx(m_hProcess,JiNengAddr,
            0x128,MEM_RELEASE);
                    ::VirtualFreeEx(m_hProcess,ThreadAdd,
            0x128,MEM_RELEASE);
                    ::VirtualFreeEx(m_hProcess,ParamAddr,
            0x128,MEM_RELEASE);
                }
            }

            我們調用的方式也就變成了:
            void CInjectCall::JianWu(int WuPosInList, int XiangZiID)
            {
                    P1_STR MyParam;
                    DWORD ParamSum;
                    BYTE tmpid 
            = 0;
                    MyParam.Param1 
            = WuPosInList;
                    MyParam.Param2 
            = XiangZiID;
                    ParamSum 
            = sizeof(MyParam);

                    InjectFunc(JianWuA, (DWORD 
            *)&MyParam,ParamSum);
            }

            P1_STR 的結構體定義如下:
            typedef struct _P1_STR{ 
                    
            int Param1;
                    
            int Param2;
                    
            int Param3;
            }P1_STR,
            *PP1_STR; 
            這樣就可以了~~~~
                  【結尾】
                   今天要說的東西就這么多,一些沒什么技術含量的東西,希望對正需要的朋友帶來幫助,也十分的感謝大家能看完我這又臭又長的破爛文章!
                   感覺,不管匯編也好,Delphi也好,VB,JAVA也罷,還是C順手,極力推薦大家學C,因為很多的東西都可以自己控制,而且又簡單明了,真的是簡約而不簡單的·~~~
                         好了,去就說這么多,希望各位大牛不要笑話,同我一樣的菜菜繼續努力,去睡覺去了~~~~
                     游戲的半成品外掛連接如下:
                     /Files/bester/ZH_Boot/ZHPlg_src.rar
            亚洲精品乱码久久久久久不卡| 97热久久免费频精品99| 久久精品国产影库免费看| 欧美精品久久久久久久自慰| 伊人久久成人成综合网222| 欧美日韩中文字幕久久久不卡 | 精品少妇人妻av无码久久| 久久免费看黄a级毛片| 久久综合亚洲色HEZYO社区| 久久久久亚洲AV成人网人人软件| 久久综合九色综合久99| 国产毛片久久久久久国产毛片| 国产精品伊人久久伊人电影| 国产精品一区二区久久精品无码| 精品免费久久久久国产一区| 久久午夜福利电影| 99精品国产综合久久久久五月天| 无码精品久久久天天影视| 国产亚洲色婷婷久久99精品| 伊人色综合久久| 亚洲国产成人久久综合碰| 亚洲AV日韩精品久久久久久久| 狠狠色丁香久久婷婷综合五月| 久久99热精品| 国内精品久久久久影院老司| 午夜精品久久久久久久久| 久久成人国产精品二三区| 精品久久人人爽天天玩人人妻| 伊人久久亚洲综合影院| 久久久无码精品亚洲日韩蜜臀浪潮| 久久国产精品久久国产精品| 久久婷婷五月综合色99啪ak| 久久综合给合久久国产免费| 韩国三级中文字幕hd久久精品 | 大香伊人久久精品一区二区| 久久99国产综合精品| 久久久久久极精品久久久| 国产精品久久午夜夜伦鲁鲁| 亚洲欧洲久久久精品| 久久se精品一区精品二区| 狠狠综合久久综合88亚洲|