How to study C && ASM Code(1)

来源:互联网 发布:xshell mac 编辑:程序博客网 时间:2024/04/19 19:36
==www。cciss。cn==
                             
                                           How to study C && ASM Code(1)

|=---------------------------=[ 从hello word重新认识C && ASM ]=------------------------=|
|=-----------------------------=[ fall<bloodfall@msn.com> ]=----------------------------=|
|=-------------------------------=[ 版权所有:www.cciss.cn ]=------------------------------=|

--[ 开篇的罗嗦

    曾经有很多朋友问过我“如何成为一名黑客”,因为本人不是什么黑客,对一些黑客攻击技术也不是
很擅长,所以每次我的回答都是一样的:)学好C、ASM、系统架构、Linux或一个*BSD系统,然后在没有
事情的业余时间通读下<<TCP/IP详解(卷一、卷二、卷三)>>。我想在学习完这些后,您可以很自豪的说
“现在很多所谓的黑客技术太差了,因为我可以做的更好:)”。
    试想一下,你在某个地方部署了sniffer,但是你却不懂TCP/IP协议,那么可能的一种情况就是你
看不懂数据包,当然也就更不知道TCP的那些标志位是干什么的了:)突然有一天,在你无意的操作中,
你发现Windows可能存在一个漏洞,但是你怎么做?因为你不懂汇编层的代码,也不会拿C来写个简单的
漏洞测试程序,那么你只能望洋兴叹了!
    其实这个系列的文档内容,在原理上来说,是想讲解C->ASM->C的一个过程,也就是说是想要大家
在学习C的基础上熟悉C到汇编的一个逆向过程而已。如果没有了这样的一个逆向工程的过程,那么是很
难提高到发现漏洞,调试溢出程序,然后书写shellcode,直到真正的完成一次溢出漏洞攻击的过程的。
虽然攻击的手段很多,但是我想溢出可能是每个攻击者会采取的最后的解决办法,也是最直接有效的解
决办法:)。通过上面的这些废话,我想大家也应该明白一个道理了,一个初学者如何更深入的进入信息
安全的伟大领域?对,这就是反编译,业界称之为逆向工程的一个东西。如果您能够非常耐心的看完我
的一些罗嗦,那么我相信您肯定可以在这个系列的文档中掌握一些您需要的技术,当然这个系列文档仅
仅是写给初学者看的。在这个系列的文档写完后,我们会进入另一个比较神秘的领域,开始我们对各种
溢出攻击、WEB攻击等的一个探讨性质的学习文档中,在这个神秘的领域,你可能会学到一些真正的攻
击手段,或者说欺骗手段。其中我首推大家学习的或许是社会工程的运用:),因为社会工程一直是我在
探讨和研究的一个方向吧:)好啦,不说废话了,我想大家或许也开始厌烦我的罗嗦了,之所以在开篇写
这个东西,只是想大家能够有耐心的看完一些东西:)

--[ 前言

    本篇的内容或许很多你已经熟悉,但是在熟悉的同时你是否考虑过一些细微的地方?这也正是这个
系列开始的一个很现实的问题。只所以要写这个教程性质的文档,无非是为了使更多的初学者从另一种
角度来学习下C语言;我的本意是在看完这个系列教程后,使大家可以在会了C语言的基础上,同时熟悉
下简单的ASM代码,并可以了解C语言的各种语法、数据类型的底层到底是什么!
    我一直感觉写这个系列的目的是使大家能够在学习的同时,也掌握例如溢出等比较复杂的信息安全
技术。希望我的这个系列可以满足大家的需求,当然如果大家有什么好的建议,请到论坛相关的板块提
问:)欢迎大家的好建议。
    废话说完了,现在说下我们开篇要讲解的内容
    《从hello word重新认识C && ASM》
    ,这个环节会讲解基本的ASM语法,并说明C程序是如何运行的:)

    注意:如果C、ASM的语法你不熟悉,建议你参考网上的资料。ASM=汇编,以后会直接喊ASM。并且我
这里不会书写任何MASM32、TASM等汇编编译器可编译的汇编代码,我们这里要学习的就是从C-->ASM-->C
的一个过程,这个连续的文档中,我们推崇逆向工程。而且在我们的学习过程中,我会讲解代码在反编译
后的各行汇编代码及指令用法:)
    虽然在提供的这个文档的压缩包内我提供了程序的源代码和相关操作的JPG图片,但是我还是建议大
家自己动手来写写代码,其实学习编程唯一的捷径就是写代码,越多越好:)
       
    提醒:希望大家在看这个文档的时候,手中有一本C或者C++的学习资料,如果有条件可以考虑也买本
汇编的学习资料。这里我推荐大家两本比较好的资料:
        《Intel汇编语言程序设计(第四版)》
        《C Primer Plus中文版(第五版)》
        以下的代码都在Windows+VC6环境编译、调试

--[ 背景内容

    如果你问一个学习过C的人,从什么地方开始学习C的?那么我想开始学的人都知道那个经典的hello
word程序,其基本的代码如下所示:
////////Code Example1////////
#include <stdio。h>
int main()
{
    printf("hello word!/n");
    return 0;
}
    那么我们就从这个简单的hello word程序开始我们的编程冒险:)
 
    如果你没有ASM的学习背景,这里我也简单的讲解下ASM的基本语法:
    我们这里用的是MASM的语法格式,如果是AT&T汇编(Linux、Unix汇编格式)那么就相反,这里暂时不
讲解AT&T格式的汇编,为了学习的方便,我们采取VC6+VC6调试器来做我们例子代码。
  mov ebx, eax ;ebx = eax,即把eax寄存器的值赋给ebx。
    这里的mov为ASM的操作指令,就好像C里面的int i = 0;是一样的道理,当然ASM还有很多的操作指令,
如:sub、add、jmp、call等等,具体的汇编指令可以参考一些ASM的书籍,推荐大家一本《Intel汇编语
言程序设计》,这本书蛮适合初学者的:)其后可以看看《IBM PC汇编语言程序设计》。
    大家在学习该教程性质的文档前,建议大家大体的看下汇编指令、寄存器等基本的概念,不需要你学
太多汇编知识,暂时也不需要您对系统架构有多熟悉,我们的这个文档学习过程会告诉你很多您认为很深
奥的计算机系统、编程的奥秘:)
 
    我想在大家开始编程冒险前,我们可以注意我们的学习态度,不要被任何的困难所吓倒。要坚信
    Nothing,So Easy:)
    同时我也希望大家在看完这个系列的文档后,对C、ASM有一种全新的认识。

----[ 开始我们的编程冒险

    首先我们从上面Code Example1的C代码开始,在开始代码编写前,我想建议大家使用VC6或者VC。NET
来完成我们的调试和反编译过程。在开始的文档中,我们仅仅使用VC来进行各种逆向的说明,其后我们会
使用IDA等反编译工具开始我们更进一步的冒险历程。
  A:打开VC6编译器。
  B:File->New->Projects->(选择)Win32 Console Application
                                                                                      ->(输入)Project Name->OK
  C:在项目中新建一个C文件,写入我们上面的代码。如下:
    /*这里为了调试的方便,把上面的代码进行了合适的改变:)使大家更清晰程序的逆向流程。*/
    #include <stdio。h>
    int main()
    {
        char *str; //声明char类型的指针变量,存储字符串
        str = "hello word!";  //变量赋值
        printf("str = %s/n", str);
        return 0;
    }
    D:编译运行下我们的程序,看看是不是存在问题?如何编译我就不用说了吧?
    E:下个断点,在str = "hello word!";  //变量赋值;
      这行按下F9键,OK,看到那个小红球了吧?看到的话就可以
      开始调试我们的代码了:)按F11开始调试我们的代码,参照本文档的JPG图片:)
    F:下面为我反编译的整个C程序的C&&ASM代码。
      --- e:/testing/lesson1/lesson1。c  ---
        1:        #include <stdio。h>
        2:        int main()
        3:        {
        00401010   push        ebp               |
        00401011   mov         ebp,esp          |
        00401013   sub         esp,44h          |
        00401016   push        ebx               |
        00401017   push        esi               |
        00401018   push        edi               |-->>这部分代码暂时不用考虑,
        00401019   lea         edi,[ebp-44h]    |    以后会解释这部分,这个部
        0040101C   mov         ecx,11h          |    分为保存函数堆栈框架,
        00401021   mov         eax,0CCCCCCCCh   |    函数入口参数等。
        00401026   rep stos    dword ptr [edi]   |
        4:         char *str; //声明char类型的指针变量,存储字符串
        5:         str = "hello word!";  //变量赋值
        /*
          //语法解释
          这句mov dword ptr [ebp-4],offset string "hello word!" (00422028)汇编代码是对
          char *str;
          str = "hello word!";
          的反编译。
          mov指令在ASM中是操作赋值指令,在这里即为把0x00422028处的值赋给dword ptr [ebp-4]
          也即: dword ptr [ebp-4] = offset string "hello word!" (00422028)
          //对该汇编语句的一些解释
          mov dword ptr [ebp-4],offset string "hello word!" (00422028)
          类似dword ptr [ebp-4]这样格式的,为内存直接操作的ASM格式,这里我们可以拿一个过程来
          分析这里的数据转换,打开Registers窗口查看寄存器EBP的数值为:0x0012FF80,为了看到ebp-4处
的赋值过程,我们按F10键执行到下条指令,然后在Memory窗口查看下ebp-4处到底存放了什么内容:)可以
参考附件中的img6 JPG图片。
          ebp = 0x0012FF80
          则 ebp-4 = 0x0012FF7C 注意是16进制的计算方法,这些知识可以google搜索。
          我们在Memory窗口查看 ebp-4处的内存数值如下:
          0012FF7C  28 20 42 00
          由于堆栈是先进后出、后进先出的结构,所以这里的排列如下:
          28        |
          20        |
          42        |-->即这里为00422028
          00        |
          咦。。。怎么ebp-4处存储的内容为00422028,也即"hello word"。唉,这就是汇编的一个赋值,虽
然从C语言来看,仅仅的一个char *str; str = "hello word!";的变量赋值过程,在汇编层就成了这样了:
      ebp-4 --> 00422028 --> "hello word!"。
          注意:[ebp-4]没有直接获取"hello word!",而是取的"hello word!"所在的地址,为什么呢?是因
为指针的作用:)。大家如果感兴趣的话,可以把 *str换成str[30]试试看其的赋值:)
          //参考下offset string "hello word!" (00422028)的数据
          下面我们看下0x00422028处的数值,请参考附件的img6 JPG图片。
          查看其内存地址的内容为:
          00422028  68 65 6C 6C 6F 20 77  hello w
            0042202F  6F 72 64 21 00 00 00  ord!。。。
            可见其内容正好是 str字符串指针的内容,由于VC6是在DEBUG模式下进行的调试,所以我们在下面的
代码中看到的是offset string "hello word!" (00422028)这样的内容,而在很多反汇编软件中,我们可能
看到的是 :
            mov  dword ptr [ebp-4],0x00422028
            这样的内容:)
            //小结
            按照上面的一些简单的分析,希望大家能够看明白一些问题:)
            到这里已经把"hello word!"赋给了[ebp-4]了。
        */
        00401028   mov         dword ptr [ebp-4],offset string "hello word!" (00422028)
        6:            printf("str = %s/n", str);
        /*
          //下面分析printf函数的调用过程。
          在开始我们的冒险前,我们先说下函数在汇编下面的参数调用过程。对于C来讲,其参数调用在汇编
中是从后面开始的,而delphi中的pascal语法从前面开始的,和C正好相反。
          例如:printf("str = %s/n", str);
                其汇编级别的参数调用为(push指令为压入堆栈,也可以理解为参数调用):
                push str;
                push "str = %s/n";
                call printf
          //下面我们开始分析这里的printf函数的过程
          mov  eax,dword ptr [ebp-4] 使寄存器eax = [ebp-4] = "hello word!",也即相当于eax为C代码
                                     中的str变量的值。
          push eax                   参数调用,push指令为压入堆栈,也可以理解为参数调用:)此时的
                                     eax相当于printf("str = %s/n", str);中的str变量。
          push offset string "str = %s/n" (0042201c) 这里压入的为我们代码里面的第一个参数
                                                     "str = %s/n",很多时候大家可能认为这里为利用
                                                     格式化字符串打印数据内容的地方,其实这里的内
                                                     容其实也是一个参数,而例如%s、%d、%i等则为格
                                                     式化的特殊字符。如果大家能够理解这里的话,那
                                                     么我首先恭喜你,你已经学会了格式化字符串漏洞
                                                     的基本原理了:)格式化字符串漏洞就是在象这样的
                                                     地方发生的,正是因为这里的例如"str = %s/n"的
                                                     字符为一个参数,而且通过我们观察汇编代码我们
                                                     也发现程序把"str = %s/n"这个放在了程序的地址
                                                     0x0042201c处,并分配了内存空间,然后在printf
                                                     函数内部对后面参数的格式化传值进行了操作。
        call printf (00401070)       call操作指令调用printf函数,如果继续按F10键,则会打印结果:)
        */
        0040102F   mov         eax,dword ptr [ebp-4]
        00401032   push        eax                                                                       
        00401033   push        offset string "str = %s/n" (0042201c)       
        00401038   call        printf (00401070)                                               
        0040103D   add         esp,8               |
        7:            return 0;                    |
        00401040   xor         eax,eax             |
        8:        }                                |
        00401042   pop         edi                 |
        00401043   pop         esi                 |-->这里的代码我们暂时不考虑,
        00401044   pop         ebx                 |   是恢复堆栈框架所做的一些
        00401045   add         esp,44h             |   事情。可能以后的学习中,
        00401048   cmp         ebp,esp             |   我们可能会在这些代码处想
        0040104A   call        __chkesp (004010f0) |   办法来利用我们的溢出攻击:)
        0040104F   mov         esp,ebp             |
        00401051   pop         ebp                 |
        00401052   ret                             |

----[ 总结   
  总算写完了,不知道大家能否看明白,这个文档其实就是简单的说了下C-->ASM的一个简单的学习过程。
或许您没有汇编基础,或许您没有编写C代码的经验,或许您看到这个文档后感觉头很大。但是我还是建议
您能够仔细的看完这个难过的学习阶段,否则很难继续下面的学习。  虽然我一直想把这个文档写的简单
些,但是。。。但是。。。我不是大学的C语言、汇编语言老师,也不是什么教授大家编程的知识:)不管我
们的这个开始成功与否,但我感觉这都是您真正步入网络攻击技术颠峰的必要之旅:)
  至于大家不熟悉C语言、不熟悉ASM编程,那么就google或者baidu下吧。大家可以到论坛相关的板块提问
问题但是拒绝回答一些“非正常的问题”,没有办法,大家都很忙,不是嘛?

----[ 参考资料
  讲解C的一本资料
  讲解汇编的一本资料
 
----[ 网上资源
  http://www。ddvip。com/program/masm/index1/index。htm
  http://www。vcok。com/class/index。asp?classid=8
  http://download。chinaitlab。com/program/files/3027。html
  http://cpp。ga-la。com/html/1/15/0510/15。htm
  http://zhidao。baidu。com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=vc+%CA%B9%D3%C3%CA%D6%B2%E1&fr=wwwt 
原创粉丝点击