以下是运行NOTEPAD.EXE,在01001EDC处OD中断结果:
01001ED6  |.  8B3D 48120001 MOV EDI,DWORD PTR DS:[<&USER32.CheckMenu>; |USER32.CheckMenuItem
01001EDC  |.  50            PUSH EAX                                 ; |hMenu
01001EDD  |.  FFD7          CALL EDI                                 ; \CheckMenuItem可以通过OD的右上角查看到EAX的值。请问如何编写一个程序 然后读取01001EDC处EAX的值呢? 

解决方案 »

  1.   


    不知道你有没有听说过OD,我们可以模仿他的思路下int 3软件断点,然后获得线程上下文就可以了。MSDN里面有大量的Debugging Functions,你可以去看下。下面是一段微型调试器的代码#include <windows.h>
    #include <stdio.h>
    #include <assert.h>int main()
    {
         DEBUG_EVENT d;
         DWORD ;
         BOOL initBP,r;
         DWORD pid;     initBP=0;
         printf("set pid=? ");
         scanf("%d",&pid);
         r=DebugActiveProcess(pid); /* 开始调试 */
         assert(r);     printf("debugging...");     for (;;)
         {
             if (!WaitForDebugEvent(&d,INFINITE)) /* 等待调试事件 */
                 assert(0);
             switch (d.dwDebugEventCode)
             {
             case CREATE_PROCESS_DEBUG_EVENT: 
             case EXIT_PROCESS_DEBUG_EVENT:
             case CREATE_THREAD_DEBUG_EVENT:
             case EXIT_THREAD_DEBUG_EVENT:
             case LOAD_DLL_DEBUG_EVENT:
             case UNLOAD_DLL_DEBUG_EVENT:
             case OUTPUT_DEBUG_STRING_EVENT:
             case RIP_EVENT:
                 =DBG_CONTINUE; /* 这些事件都不需要处理,让目标直接运行 */
                 break;
             case EXCEPTION_DEBUG_EVENT:
                 if (initBP) 
                 {
                     =DBG_EXCEPTION_NOT_HANDLED; /* 没处理就是没处理*/
                 }
                 else
                 {
                     initBP=1;
                     =DBG_CONTINUE; /* 初始断点要特别留意 */
                 }
                 break;
             }
             if (!ContinueDebugEvent(
                 d.dwProcessId,
                 d.dwThreadId,)) /* 继续执行目标程序 */
                 assert(0);
             if (d.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT)
                 break;
         }
         printf("stopped\n");     return 0;
    }
    如上是直接附加到活动进程,如果我们学着OD,加载进程后,在OEP那里断下的话,用CreateProcess创建进程,标志位打上Debug标志即可,类似下面这样
    STARTUPINFO   st   =   {0}; 
    PROCESS_INFORMATION   pro   =   {0}; 
    st.cb   =   sizeof(st); 
    CreateProcess(NULL,   "d:\\test.exe ",   NULL,   NULL,   TRUE,
    DEBUG_ONLY_THIS_PROCESS, 
    NULL,   NULL,   &st,   &pro); CloseHandle(pro.hThread); 
    CloseHandle(pro.hProcess); 
    DEBUG_EVENT   dbe; 
    BOOL   rc; 
    while(WaitForDebugEvent(&dbe,   INFINITE)) 

      if(dbe.   dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) 
       break; 
      ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId ,DBG_CONTINUE   ); 
    }
    //有的代码我就略过了,在上课,不方便写很多软件断点(INT3):对应的异常是 EXCEPTION_BREAKPOINT,处理方式为恢复代码为原来字节,并将EIP减一,并设置单步以便进入单步后重新设置这个一般断点。那么现在要解决的问题就剩一个了,就是写入断点int3,OEP那边断下之后就要写,然后开始执行。这个可以用WriteProcess实现,当你初次加载之后,进程虽然断下来了,但是PE已经加载进了内存空间中。
    根据偏移,把int 3对应的十六进制0xCC指令写入断下来之后,用GetThreadContext获得线程上下文就可以得到寄存器的值了这里有些注意点,看下面的代码
    if (r->ExceptionCode==EXCEPTION_BREAKPOINT) /* 触发了断点中断 */            
    {              /* 根据中断地点查找断点记录 */              
    bp=find(ps->bps,MAX_BP,(DWORD)r->ExceptionAddress);               
    if (bp) /* 是调试器安置的断点 */              
    {                
    t=find(ps->ts,MAX_THRD,d.dwThreadId); /* 取线程上下文 */                
    memset(&ctx,0,sizeof(ctx));                
    ctx.ContextFlags=CONTEXT_FULL;                
    f=GetThreadContext(t->h,&ctx);                
    assert(f);                
    ctx.Eip--;          /* 将指令指针值减1 */                
    ctx.EFlags|=TF_BIT; /* 打开CPU单步标记 */               
    f=SetThreadContext(t->h,&ctx); /* 向目标写入修改过的上下文 */                
    assert(f);                       
    ps->write_back=bp; /* 标记该进程在单步结束后准备写回的断点 */               
    safe_write(ps->h,bp->addr,bp->c); /* 写入被断点覆盖的代码 */               
    on_bp(d.dwProcessId,d.dwThreadId,bp->addr); /* 用户处理 */                        
    suspend_except(ps->ts,d.dwThreadId); /* 挂起除异常线程外的所有线程 */               
    =DBG_CONTINUE;              
    }
    }
      

  2.   

    可以使用inline hook,写一个dll注入到notepad.exe
      

  3.   

    嘿嘿  OD我熟悉,不过看了 Tr0j4n  才知道的方法。得把int3 中断写入目标的代码行。然后再获取
    writeprocememory
      

  4.   

    罗云斌的汇编教程里面有patch程序的例子,其中有一个就是用debug Api来对程序进行patch的。
      

  5.   

    filememory,好象是windwos核心编程里看到过
      

  6.   

    用OllyICE反汇编,下断点,跟踪。
      

  7.   

    运行中就直接读内存撒。
    直接看代码:
              HANDLE processH=::OpenProcess(PROCESS_ALL_ACCESS,false,processid);
            //processid 为进程PID
             //获取PID方法很多,可以通过任务管理器查看...
            //可以用枚举进程方式取得,或者获取窗口再获取进程ID等...
    if(!processH)
    {
    return;//打开进程失败,返回
    }
    //读指定进程 内存数据  
    DWORD byread;
    DWORD xuyao;
    LPVOID pbase=(LPVOID)0x01001EDC;//把你的地址转换成通用指针
    ::ReadProcessMemory(processH,pbase,&xuyao,4,&byread);
    //如果ReadProcessMemory成功,0x01001EDC的数据就保存在了变量 xuyao里了。
      

  8.   

    这个也太不靠谱了……应该先用int 0x3替换目标程序原来的指令,
    目标线程被中断后,再查看它的线程上下文(好象是叫这个名字)
      

  9.   

    ReadProcessMemory
    WriteProcessMemory这些不行吗?
      

  10.   

    DebugActiveProcess挂上目标进程
    用WriteProcessMemory在目标进程01001EDC处插入INT3指令
    程序收到调试事件后用GetThreadContext读取寄存器Context信息
      

  11.   

    在写游戏辅助时学用到,但EAX的值是常变化的,一般是向上查找修改EAX值的语句,或是否是个固定值。
    这个地方应该是USER32.CheckMenuItem函数的参数
      

  12.   

    学习编程已经不再是少数计算机专业人员的事情了,就如同计算机深入到我们生活的每一个角落一样,学习编程的人也是越来越多。由于现在网络信息资源丰富,大多数人都选择了自学。我自幼自学编程十余年,多少积累了一些经验和方法,想通过这里给这些初学的编程自学者一些个人的建议。 建议一:自学也需要看书 自学只是说没有专门的老师手把手教你,并不是说连书本都可以不要了。有人天天来问我一些很基础的概念问题,我问他:“这些概念书上不都写得很明白吗?”他回答:“我没有书。”如果没有书,那么你很难在脑子里形成一个较为整体性的认识,所有了解到的知识都是支离破碎的。且不说大多数人没有精力回答你这些问题,即使回答了,很多东西也不是三言两语就能说清的,很多高手说出来的都是他们自己的理解,这些理解或许很有意味,但也许费了你半天的脑子却怎么也搞不明白。一本书,即使不是什么经典之著,它也可以向你提供一个大体完整的框架,成为你自学过程中的一个向导。这里要说的是:网上电子教程资源丰富,看看无妨,但手中至少应有一本印刷的书——毕竟网上的教程鱼龙混杂,其作者也许并不精通此道,很难分辨其质量好坏。 建议二:学编程更需要实践 书是有了,可是整天抱着书也不成。编程最怕的就是纸上谈兵,我看到有的初学者,看完了大半本书,和我说起循环函数来头头是道,却连编译器长什么样都没有见过。真要他写几行程序,便是错误百出。我的建议是,无论你涉及编程的时间是多么地短,无论你目前学到的知识多么地少,你都应该不断地尽自己所能去编写一些小程序——即使是把书上的“Hello, World!”亲手输入进去运行一遍,都能让你的编程能力有着极速地提高。 建议三:编程是创造,不是默写 有人甚至打算用题海战术来学习编程——这完全没有理解编程的内涵。仅仅通过“欣赏”别人写的代码也无法学好编程。有一点需要明白:编程是一个创造的过程。编程的意义在于:通过程序的形式,教计算机如何去完成一项任务。写代码只是形式,真正重要的是如何完成特定的任务。学习别人的代码固然是很有用的,可以学习别人的思想;但是如果仅仅是记忆了一些别人写好的代码,就希望能通过拼拼凑凑成为自己的程序,那是基本不可能的。我的建议是:在自己编写程序,进行创造的过程中,借鉴前人程序中的思想方法——而不是整天处于复制粘贴的状态中。 建议四:好习惯要从开始做起 所谓“不以善小而不为”,等坏习惯养成了,再改就困难了。因此,类似写程序要注意缩进、为变量和函数起有意义的名字、大小写的使用、行末分号的注意等等,要从一开始做起。很多人对这些善意的提醒不屑一顾,觉得多此一举,浪费时间。其实,如果真的能严格地去做,它们反而可以帮你节省许多时间。 建议五:不必太刨根问底 “打破沙锅问到底”确实表现了一种钻研的精神,不过我还是建议初者学,有的时候,不必太刨根问底。编程的相关知识都是盘根错节交织在一起的,大多数问题深挖下去会越说越复杂,对于知识掌握不多的初学者来说,只能是越来越糊涂。很多东西,时间长了,随着知识了解得深入,自然而然会明白。就像刚刚学英语的时候,你知道“goodbye”是再见就足够了,难道非要把这个good和再见的关系先弄个水落石出吗?作为初学者,最重要的是尽快地能全面地了解整个知识的全貌,在单独的知识点上,暂时不需要太深入。可以等知识经验丰富之后,再回头来研究。 
      

  13.   

    我想说,我解决的办法就是在你要取的寄存器的值的下面一行愣jmp到另外一段代码,这之前要把下面这一行保存5个字节,另外一段代码把寄存器的值写入到一个你指定的内存后把保存的代码写到尾部,然后在愣jmp到你HOOK位置的下面5个字节,远程线程即可,这个方法一般用于盗号,源码我就不上了,其中最好是自己实现内存拷贝,不然你会迷糊的。
      

  14.   

    搞的这么复杂,,直接HOOK 就行拉