• <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>

            記錄一些學(xué)習(xí)小事

            Work hard

            統(tǒng)計(jì)

            留言簿

            閱讀排行榜

            評(píng)論排行榜

            spy++和游戲修改器

            這幾天做了兩個(gè)東西,spy++ 和游戲修改器。 spy++ 就是模仿 vs的那個(gè)工具spy++ 。游戲修改器,就是暴力搜索內(nèi)存,找到我們關(guān)心的數(shù)據(jù),然后進(jìn)行更改。
            總之這些東西做過(guò)之后感覺(jué)就是都不難,但是在做的時(shí)候多少會(huì)感覺(jué)點(diǎn)吃力。唉,功力不夠啊。繼續(xù)修煉……
            閑下來(lái)無(wú)事,記錄下它們的過(guò)程吧。
            spy++ 分析(用vs2005做的——)
            spy++ 需要拖動(dòng)一個(gè)小圖標(biāo) 然后移動(dòng)到別的窗口上(本窗口也可以),然后畫出窗口的矩形,得到窗口的一些信息。
            拖動(dòng)的這個(gè)小圖標(biāo),是一個(gè)picture conctrl控件 ,屬性的type改成icon 也就是加載一個(gè)icon圖標(biāo),在屬性imag里把圖標(biāo)選上。
            給這個(gè)控件添加一個(gè)類,在這個(gè)類里做這個(gè)控件的 小圖標(biāo)拖動(dòng)操作,即 lbuttondown的時(shí)候 把鼠標(biāo)加載成 小圖標(biāo),把picture里的icon換成空心的。
            當(dāng)鼠標(biāo)抬起的時(shí)候把鼠標(biāo)換回來(lái)原先的光標(biāo),然后再把picture里的icon換成有小圖標(biāo)的那個(gè)圖標(biāo)。
            這里要主次 要把鼠標(biāo)設(shè)成全局有效,要不然的話,鼠標(biāo)位置出了這個(gè)picture的范圍就失效了。函數(shù)是 SetCapture()
            然后再lbuttonup的時(shí)候記得 要釋放。ReleaseCapture();
                       就是這幾個(gè)圖標(biāo)。吼吼。
            把這個(gè)小圖標(biāo)托到 窗口上的時(shí)候怎么在窗口上畫出矩形呢? 
            當(dāng)然是先得到這個(gè)矩形了。我要先得到這個(gè)窗口的句柄,我們才能得到windowrect 然后才能畫。
            所以各 下一步就是WindowFromPoint(Point)傳一個(gè)鼠標(biāo)點(diǎn) 然后得到這個(gè)點(diǎn)的window的hWnd了 哈,很強(qiáng)大的函數(shù)啊。
            得到窗口句柄就好辦了。GetWindowRect得到矩形區(qū)域啊,然后用windowdc 畫,用windowdc的原因就是,我們要在整個(gè)桌面上都能畫。
            這里畫這個(gè)矩形有個(gè)技巧,我們要畫出來(lái),但是當(dāng)我們不需要這個(gè)矩形的時(shí)候我們還要給這個(gè)顏色畫回原來(lái)的背景色。這里算是整個(gè)程序的一個(gè)難點(diǎn),考驗(yàn)畫圖工夫。
            dc設(shè)備中默認(rèn)選入的是一個(gè)黑色畫筆,一個(gè)白色畫刷,也就是說(shuō)正常我們畫矩形的話會(huì)畫出黑邊白底得矩形,現(xiàn)在我們要透明的底,然后畫的黑邊還要可畫回原先的背景色。有一個(gè)函數(shù)通過(guò)dc調(diào)用  dc.SetROP2(R2_NOTXORPEN);參數(shù)傳這個(gè)同或運(yùn)算,這個(gè)函數(shù)的意思就是,拿你設(shè)備中的畫筆畫刷 去跟背景色運(yùn)算,同或運(yùn)算。
            比如背景有個(gè)顏色是10010100011   你的畫刷顏色是白色 也就是111111111111(比如就這么多位)  白色因?yàn)槭?55,255,255所以都是1  
            然后進(jìn)行同或運(yùn)算得到的是什么?是10010100011(同或,同則1,不同則0)!也就說(shuō) 還是背景色,這就做到了畫刷透明。然后畫筆是黑色,0000000000
            跟背景色同或運(yùn)算的到得是01101011100 這個(gè)。然后這個(gè)就是真正畫到屏幕上顯示出來(lái)的顏色。怎么在把這個(gè)顏色畫沒(méi)呢?大家在用這個(gè)黑色的畫筆畫一下,在同或運(yùn)算看看結(jié)果是什么?10010100011 看看是不是又變回去了?吼吼。等會(huì)下面貼代碼畫圖這里的。
            這個(gè)畫圖就完事了。而且窗口句柄我們也通過(guò)windowfrompoint得到了。有了窗口句柄我們能得到很多東西了。
            比如說(shuō)窗口類名GetClassName
            窗口標(biāo)題GetWindowText
            窗口矩形GetWindowRect
            窗口id等信息GetWindowLong
            進(jìn)程id   GetWindowThreadProcessId
            進(jìn)程路徑 OpenProcess()   GetModuleFileNameEx();

            還可以向窗口中發(fā)消息 sendmessage(這個(gè)比較好玩,可以拿你的spy++去關(guān)閉別人的窗口。
            然后把他設(shè)置到窗口上就可以了。
            代碼貼一小段。

            void CMyPic::OnTimer(UINT_PTR nIDEvent)
            {
                POINT p;
                ::GetCursorPos(
            &p);
                hWnd
            =::WindowFromPoint(p);
                CRect rect;
                ::GetWindowRect(hWnd,
            &rect);
                CWindowDC dc(NULL);
                CPen redpen(PS_SOLID,
            3,RGB(255,0,0));
                dc.SelectObject(
            &redpen);
                dc.SetROP2(R2_NOTXORPEN);
                dc.Rectangle(rect);
                
            //顯示回去 就向沒(méi)畫一樣
                Sleep(300);
                dc.Rectangle(rect);
                ReleaseDC(
            &dc);
                CStatic::OnTimer(nIDEvent);
            }

            這個(gè)畫圖在timer里畫,能做到 閃動(dòng)的巨型。(我選的紅色畫筆,你可以把紅色跟背景同或算算,跟黑色是一樣的,在畫一次就能畫回來(lái)背景色)
            下面的代碼是 寫我的spy++的第一頁(yè)的代碼

            void CMyspyDlg::UpdataWindowNormal(HANDLE hWnd)
            {
             CString str;
             int state=((CButton *)GetDlgItem(IDC_CHECK1))->GetCheck();
             //窗口句柄
             if (state==BST_CHECKED)
             {
              str.Format(_T("%p"),hWnd);
             }
             else
             {
              str.Format(_T("%d"),hWnd);
             }
             m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_HANDLE)->SetWindowText(str);
             //窗口類名
             TCHAR tempTC[50];
             GetClassName((HWND)hWnd,tempTC,49);
             m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_CLASSNAME)->SetWindowText(tempTC);
             //窗口標(biāo)題
             ZeroMemory(tempTC,100);
             ::GetWindowText((HWND)hWnd,tempTC,49);
             if (*tempTC==_T('\0'))
             {
              m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_TITLE)->SetWindowText(_T("無(wú)"));
             }
             else
             {
              m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_TITLE)->SetWindowText(tempTC);
             }
             //窗口矩形
             CRect rect;
             ::GetWindowRect((HWND)hWnd,&rect);
             str.Empty();
             if (state==BST_CHECKED)
             {
              str.Format(_T("x=%x,y=%x,width=%x,hight=%x"),rect.left,rect.top,rect.Width(),rect.Height());
             }
             else
             {
              str.Format(_T("x=%d,y=%d,width=%d,hight=%d"),rect.left,rect.top,rect.Width(),rect.Height());
             }
             m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_WINRECT)->SetWindowText(str);
             //窗口id
             str.Empty();
             LONG l=::GetWindowLong((HWND)hWnd,GWL_ID);
             str.Format(_T("%ld"),l);
             m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_WINID)->SetWindowText(str);
             //進(jìn)程id
             DWORD dword;
             ::GetWindowThreadProcessId((HWND)hWnd,&dword);
             str.Empty();
             if (state==BST_CHECKED)
             { 
              str.Format(_T("%p"),dword);
             }
             else
             {
              str.Format(_T("%d"),dword);
             }
             m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_PROCESSID)->SetWindowText(str);
             //程序路徑
             HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dword);
             TCHAR src[200];
             GetModuleFileNameEx(hProcess,NULL,src,199);
              m_TabCtrl.m_dlg[0].GetDlgItem(IDC_EDIT_PROSRC)->SetWindowText(src);
            }

            ======================================================================
            效果圖

            ======================================================================

            好了 下面記錄下游戲修改器
            其實(shí)我用的方法很笨的,但是比較簡(jiǎn)單。改成功了植物大戰(zhàn)僵尸中的太陽(yáng)值。
            =======================================================================
            效果圖

            =======================================================================
            這個(gè)游戲修改 就是讀內(nèi)存,值進(jìn)行比較,然后找到一些跟你輸入的值相同的地址,記錄在鏈表中,然后讓這個(gè)值變化,在對(duì)鏈表進(jìn)行搜索
            如果鏈表中的地址中的值也變化了,正確的地址就在這鏈表里,繼續(xù)變化值,之后最后地址確定下來(lái)為止,地址確定下來(lái)之后就可以修改了。
            其中用到得函數(shù) 先是 快照,(我在前面做任務(wù)管理器中寫到過(guò)) 得到進(jìn)程id 進(jìn)程名等。
            然后用openprocess打開(kāi)方式用要可讀,可寫,或者獲得所有權(quán)PROCESS_ALL_ACCESS。得到進(jìn)程的句柄。
            然后通過(guò)進(jìn)程的句柄讀進(jìn)程中的數(shù)據(jù)ReadProcessMemory因?yàn)樘摂M內(nèi)存共有4gb  后2gb是系統(tǒng)用,還有前多少K(不同系統(tǒng)不一樣)也系統(tǒng)用。所以我們只搜索前兩gb ,但是前面那些系統(tǒng)的我們就忽略了,畢竟是小數(shù),不在乎多讀那點(diǎn)了。
            ReadProcessMemory這個(gè)函數(shù)第一個(gè)參數(shù)是進(jìn)程handle,第二個(gè)參數(shù) 是基址(即從那個(gè)位置開(kāi)始讀,是一個(gè)地址),第三個(gè)參數(shù)是讀出的buff 第四個(gè)是讀的大小。 由于內(nèi)存頁(yè)是4kb 我們?yōu)榱俗x的速度快 所以我們每次就讀4kb。 讀出這4kb 放入buff中 然后 拿我們要找的數(shù)值比如是100,(我們假定我們的數(shù)是2字節(jié)),在4kb中1字節(jié)1字節(jié)的向后走,兩字節(jié)兩字節(jié)的比較 如果等于100則加入鏈表
            DWORD dOneGB=1024*1024*1024;//1gb的地址
             DWORD dBase=0;//基址是0
             DWORD dOnePage=4*1024;//一個(gè)內(nèi)存頁(yè)4kb
             BYTE buffer[4*1024];//裝一個(gè)內(nèi)存也
             WORD value;
             CString str;
             int pos=0;
             POSITION listpos;
            //得到我們窗口上輸入的值 value
             GetDlgItem(IDC_EDIT_INPUT)->GetWindowText(str);
             value=_wtoi(str);
             for (dBase;dBase<dOneGB*2;dBase+=dOnePage)//遍歷2gb每次 加一頁(yè)  4kb
             {
              if(ReadProcessMemory(hProcess,(LPCVOID)dBase,buffer,4*1024,NULL))//讀一個(gè)頁(yè),因?yàn)檫@個(gè)讀取是不一定成功的所以加if(有的內(nèi)存系統(tǒng)不讓你讀)
              { 
            //進(jìn)行比較 如果相同加入鏈表CList m_Data;
               for(DWORD b=0;b<dOnePage-1;b++)
               {
                WORD tempword=*((WORD *)(buffer+b));
                if (tempword==value)
                {
                 if (pos==0)//如果是頭結(jié)點(diǎn)就 加在頭上,之后就加在后邊
                 {
                  listpos = m_Data.AddHead(dBase+b);
                  pos++;
                 }
                 else
                 {
                  listpos = m_Data.InsertAfter(listpos,dBase+b);
                 }
                }
               }
              }
             }

            這樣這個(gè)第一次搜索就完成了。搜出了一堆 等于100的值 的地址,放入了鏈表
            下次就是   改變100為150,然后再鏈表中搜索等于150的。
            int dataCount=m_Data.GetCount();
             pp=m_Data.GetHeadPosition();
              for (int i=0;i<dataCount;i++)
              {
               DWORD tempvalue=m_Data.GetNext(pp);
            //根據(jù)基址讀出兩個(gè)字節(jié)的數(shù),然后跟value比較
               ReadProcessMemory(hProcess,(LPCVOID)tempvalue,&buff,2,NULL);
               if(buff==value)
               {
               if (head)
               {
                li.AddHead(tempvalue);
                head=FALSE;
               }
               else
               {
                li.AddTail(tempvalue);
               }
               }
              }
            哈哈,然后最后就搜到了那個(gè)值得地址,,然后根據(jù)這個(gè)地址改變 其中的值就行了

            WriteProcessMemory(hProcess,(LPVOID)address,&newValue,2,NULL);
            思路倒是很簡(jiǎn)單,寫的時(shí)候總會(huì)出錯(cuò)誤,或是內(nèi)存錯(cuò)誤或是中斷的,要耐心調(diào)調(diào)。
            為了植物大戰(zhàn)講師的無(wú)限陽(yáng)光,吼吼。go


             

            posted on 2011-08-09 15:06 陳曉 閱讀(4043) 評(píng)論(8)  編輯 收藏 引用

            評(píng)論

            # re: spy++和游戲修改器 2011-08-10 10:05 zuhd

            改變100為150,然后再鏈表中搜索等于150的。

            這樣啊,牛!  回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器[未登錄](méi) 2011-08-10 12:09 heroboy

            先用VirtualQueryEx得到內(nèi)存的屬性。有些內(nèi)存區(qū)域可能是代碼或者文件的映射,不需要查詢。  回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器[未登錄](méi) 2011-08-10 12:50 陳曉

            對(duì)!這位兄臺(tái)說(shuō)的很對(duì),呵呵,當(dāng)時(shí)就為了練讀取函數(shù)了,沒(méi)有弄這些細(xì)節(jié),如果把你這個(gè)條件方里的話會(huì)快一些的。@heroboy
              回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器[未登錄](méi) 2011-08-10 12:51 陳曉

            恩呢,如果用150搜了之后還是還有好些地址的話,那么就繼續(xù)改變這個(gè)值,在搜,我搜植物大戰(zhàn)講師里的陽(yáng)光值的話,一般3次就能找到正確的那個(gè)。@zuhd
              回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器 2011-08-10 14:02 coolypf

            可以做個(gè)金山游俠2012版!  回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器[未登錄](méi) 2011-08-10 14:57 陳曉

            @coolypf
            額樓上的哥們說(shuō)笑啦,哈哈,小弟水平不行啊,哈哈。我寫的這點(diǎn)東西都是很簡(jiǎn)單的,難得也不會(huì)啊- -我是現(xiàn)學(xué)現(xiàn)賣。。。  回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器 2011-08-10 17:23 他她女鞋

            看起來(lái)還挺不錯(cuò)的東東。  回復(fù)  更多評(píng)論   

            # re: spy++和游戲修改器[未登錄](méi) 2011-08-12 21:41 陳曉

            @他她女鞋
            謝謝支持…  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久精品水蜜桃av综合天堂| 国内精品人妻无码久久久影院导航| 亚洲欧洲久久av| 亚洲&#228;v永久无码精品天堂久久 | 久久国产高清一区二区三区| 久久人人爽人人澡人人高潮AV| 精品无码久久久久国产动漫3d| 精品国产一区二区三区久久久狼| 久久精品国产亚洲欧美| 久久综合色之久久综合| 香蕉久久夜色精品升级完成| 香蕉99久久国产综合精品宅男自 | 国产免费久久精品丫丫| 老男人久久青草av高清| 大香网伊人久久综合网2020| 日韩欧美亚洲综合久久影院Ds | 精品久久久久久99人妻| 亚洲va中文字幕无码久久| 伊人久久大香线蕉影院95| 精品久久久久久久久午夜福利| 精品久久久久久无码免费| 久久99精品久久久久久动态图| 久久精品国产99久久香蕉| 精品一区二区久久| 亚洲AV无一区二区三区久久| 久久噜噜久久久精品66| 草草久久久无码国产专区| 欧美噜噜久久久XXX| 国产精品一久久香蕉国产线看 | 激情五月综合综合久久69| 久久精品国产亚洲77777| 色综合合久久天天给综看| 久久精品国产99国产精偷 | 亚洲色大成网站www久久九| 久久强奷乱码老熟女| 久久99热狠狠色精品一区| 亚洲AV日韩AV永久无码久久| 久久亚洲sm情趣捆绑调教| 久久婷婷五月综合色奶水99啪 | 狠狠色丁香久久综合婷婷| 亚洲欧美伊人久久综合一区二区 |