逆向工程 订阅
逆向工程(又称逆向技术),是一种产品设计技术再现过程,即对一项目标产品进行逆向分析及研究,从而演绎并得出该产品的处理流程、组织结构、功能特性及技术规格等设计要素,以制作出功能相近,但又不完全一样的产品。逆向工程源于商业及军事领域中的硬件分析。其主要目的是在不能轻易获得必要的生产信息的情况下,直接从成品分析,推导出产品的设计原理。逆向工程可能会被误认为是对知识产权的严重侵害,但是在实际应用上,反而可能会保护知识产权所有者。例如在集成电路领域,如果怀疑某公司侵犯知识产权,可以用逆向工程技术来寻找证据。 展开全文
逆向工程(又称逆向技术),是一种产品设计技术再现过程,即对一项目标产品进行逆向分析及研究,从而演绎并得出该产品的处理流程、组织结构、功能特性及技术规格等设计要素,以制作出功能相近,但又不完全一样的产品。逆向工程源于商业及军事领域中的硬件分析。其主要目的是在不能轻易获得必要的生产信息的情况下,直接从成品分析,推导出产品的设计原理。逆向工程可能会被误认为是对知识产权的严重侵害,但是在实际应用上,反而可能会保护知识产权所有者。例如在集成电路领域,如果怀疑某公司侵犯知识产权,可以用逆向工程技术来寻找证据。
信息
动    力
确认竞争产品是否侵权专利或版权
作    用
保护知识产权所有者
中文名
逆向工程
又    称
逆向技术
逆向工程产生动机
需要逆向工程的原因如下:●接口设计。由于互操作性,逆向工程被用来找出系统之间的协作协议。●军事或商业机密。窃取敌人或竞争对手的最新研究或产品原型。●改善文档。当原有的文档有不充分处,又当系统被更新而原设计人员不在时,逆向工程被用来获取所需数据,以补充说明或了解系统的最新状态。●软件升级或更新。出于功能、合规、安全等需求更改,逆向工程被用来了解现有或遗留软件系统,以评估更新或移植系统所需的工作。●制造没有许可/未授权的副本。●学术/学习目的。●去除复制保护和伪装的登录权限。●文件丢失:采取逆向工程的情况往往是在某一个特殊设备的文件已经丢失了(或者根本就没有),同时又找不到工程的负责人。完整的系统时常需要基于陈旧的系统上进行再设计,这就意味着想要集成原有的功能进行项目的唯一方法,便是采用逆向工程的方法,分析已有的碎片进行再设计。●产品分析:用于调查产品的运作方式,部件构成,估计预算,识别潜在的侵权行为。
收起全文
精华内容
参与话题
问答
  • 逆向工程

    2020-05-20 07:59:00
    1. 首先我们需要知道什么是逆向工程 mybatis逆向工程简称MBG。它是专门为MyBatis框架使用者定制的代码生成器。 可以快速的根据表生成对应的映射文件,接口,以及Bean类对象。 逆向工程只能对单表生成CRUD操作 它可以...

    1. 首先我们需要知道什么是逆向工程

    mybatis逆向工程简称MBG。它是专门为MyBatis框架使用者定制的代码生成器。
    可以快速的根据表生成对应的映射文件接口,以及Bean类对象

    逆向工程只能对单表生成CRUD操作
    它可以帮我们对比数据库表之后,生成大量的这个基础代码。
    这些基础代码有:
    1、数据库表对应的javaBean对象
    2、这些javaBean对象对应的Mapper接口
    3、这些Mapper接口对应的配置文件

      	<!-- 去掉全部的注释 -->
    	<commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
    

    准备数据库表

    create database mbg;
    use mbg;
    
    create table t_user(
    	`id` int primary key auto_increment, /*主键自增*/
    	`username` varchar(30) not null unique,/*用户名非空且唯一*/
    	`password` varchar(40) not null,/*密码非空*/
    	`email` varchar(50)/*邮箱*/
    );
    
    insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@caiwan.com');
    insert into t_user(`username`,`password`,`email`) values('wzg168','123456','admin@caiwan.com');
    
    create table t_book(
    	`id` int primary key auto_increment,
    	`name` varchar(50),
    	`author` varchar(50),
    	`price`	decimal(11,2),
    	`sales`	int,
    	`stock` int
    );
    
    ## 插入初始化测试数据
    insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
    values(null , '3天精通java' , '菜丸' , 55 ,555 , 5);
    
    insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
    values(null , 'JVM底层原理' , '菜丸' , 66 , 666 , 6);
    
    insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
    values(null , '数据结构' , '菜丸' , 77, 777 , 7);
    
    select * from t_user;
    select * from t_book;
    

    逆向工程配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
        <context id="DB2Tables" targetRuntime="MyBatis3">
    
            <!-- 去掉全部的注释 -->
            <commentGenerator>
                <property name="suppressAllComments" value="true" />
            </commentGenerator>
    
            <!-- 修改 数据库的 连接属性 -->
            <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/mbg"
                            userId="root"
                            password="root">
            </jdbcConnection>
    
            <javaTypeResolver >
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
    
            <!--配置生成javaBean的
                    targetPackage javaBean的包名
                    targetProject 生成在哪个项目目录下
            -->
            <javaModelGenerator targetPackage="com.caiwan.pojo" targetProject=".\mybatis-mbg\src">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
    
            <!--
                       配置生成的Mapper.xml配置文件
                                    targetPackage javaBean的包名
                                    targetProject 生成在哪个项目目录下
            -->
            <sqlMapGenerator targetPackage="com.caiwan.mapper"  targetProject=".\mybatis-mbg\src">
                <property name="enableSubPackages" value="true" />
            </sqlMapGenerator>
            <!-- 配置生成Mapper接口 -->
          <javaClientGenerator type="XMLMAPPER" targetPackage="com.caiwan.mapper"
                                 targetProject=".\mybatis-mbg\src">
                <property name="enableSubPackages" value="true" />
            </javaClientGenerator>
            <!--
                数据库一个表对应一个table标签
                    tableName是表名
                    domainObjectName 设置生成的类名
            -->
            <table tableName="t_user" domainObjectName="User" />
            <table tableName="t_book" domainObjectName="Book" />
        </context>
    </generatorConfiguration>
    

    执行逆向工程的代码:

    package com.caiwan.mbg.runner;
    
    import org.mybatis.generator.api.MyBatisGenerator;
    import org.mybatis.generator.config.Configuration;
    import org.mybatis.generator.config.xml.ConfigurationParser;
    import org.mybatis.generator.exception.InvalidConfigurationException;
    import org.mybatis.generator.exception.XMLParserException;
    import org.mybatis.generator.internal.DefaultShellCallback;
    import java.io.File;
    import java.io.IOException;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MbgRunner {
    
        public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
            List<String> warnings = new ArrayList<String>();
            boolean overwrite = true;
            File configFile = new File("mybatis-mbg/mbg.xml");
            ConfigurationParser cp = new ConfigurationParser(warnings);
            Configuration config = cp.parseConfiguration(configFile);
            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
        }
    }
    

    生成测试代码:

    package com.caiwan.test;
    import com.caiwan.mapper.BookMapper;
    import com.caiwan.pojo.Book;
    import com.caiwan.pojo.BookExample;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.BeforeClass;
    import org.junit.Test;
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.util.List;
    
    public class BookMapperTest {
        static SqlSessionFactory sqlSessionFactory;
    
    	// @BeforeClass在当前类的所有测试方法之前执行。注解在【静态方法】上。
        @BeforeClass
        public static void init() throws IOException {
            sqlSessionFactory= new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        }
    
    
        @Test
        public void countByExample() {
            SqlSession session = sqlSessionFactory.openSession();
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
                // 创建一个条件类
                BookExample bookExample = new BookExample();
                // 创建一个查询条件
                BookExample.Criteria criteria = bookExample.createCriteria();
    
    //            where xxx = xxx and xxx = xxx;
    //            where xxx = xxx or xxx = xxx;
    
                // 查询价格大于16的图书有几条记录
    //            criteria.andPriceGreaterThan(new BigDecimal(16));
                // 查询销量大于10 , 且 库存 大于50的记录
    //            criteria.andSalesGreaterThan(10);
    //            criteria.andStockGreaterThan(50);
    
                // 查询销量大于10 , 或 库存 大于50的记录
                criteria.andSalesEqualTo(10);
                bookExample.or().andStockGreaterThan(50);
    
                // count() 用于查询数量的方法
                // count 用于查询数量的
                // ByExample按条件来查询
                int i = mapper.countByExample(bookExample);
                System.out.println(i);
            } finally {
                session.close();
            }
        }
    
        @Test
        public void deleteByExample() {
            SqlSession session = sqlSessionFactory.openSession();
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    //            mapper.deleteByExample(null);// 只要条件是空,就是全表操作
                BookExample bookExample = new BookExample();
                bookExample.createCriteria().andSalesGreaterThan(10000);
    
                mapper.deleteByExample(bookExample);
    
                session.commit();
            } finally {
                session.close();
            }
    
        }
    
        @Test
        public void deleteByPrimaryKey() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    
                mapper.deleteByPrimaryKey(8);
    
                session.commit();
            } finally {
                session.close();
            }
    
        }
    
        @Test
        public void insert() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    
                mapper.insert(new Book(null,"刷leetcode的一百道题", "菜丸1", new BigDecimal(1234), 1234,1234));
                mapper.insert(new Book(null,"java从入门到放弃", "菜丸2", new BigDecimal(1234), 1234,1234));
    
                session.commit();
    
            } finally {
                session.close();
            }
    
        }
    
        @Test
        public void insertSelective() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    
                Book book = new Book(null,"数据库", null,null,100,100);
    
                // 方法末尾Selective就表示操作的时候,不带null值的列
    //            mapper.insertSelective(book);// null列不在操作范围内
                mapper.insert(book);// null列一样在操作范围内
    
                session.commit();
            } finally {
                session.close();
            }
        }
    
        @Test
        public void selectByExample() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
                BookExample bookExample = new BookExample();
                bookExample.createCriteria().andIdBetween(1,10);
                // 设置排序字段
                bookExample.setOrderByClause(" price desc ");
    //            List<Book> books = mapper.selectByExample(null);// 条件为null,就整表操作
                List<Book> books = mapper.selectByExample(bookExample);// 有条件
                books.forEach(System.out::println);
            } finally {
                session.close();
            }
        }
    
        @Test
        public void selectByPrimaryKey() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
                Book book = mapper.selectByPrimaryKey(6);
                System.out.println(book);
    
            } finally {
                session.close();
            }
        }
    
        @Test
        public void updateByExampleSelective() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    
                Book book = new Book(null,"忽略null的列", null, null,1234,124);
                BookExample bookExample = new BookExample();
                bookExample.createCriteria().andIdGreaterThan(8);
                /**
                 * 根据条件来进行更新,而且不带null的列
                 */
                mapper.updateByExampleSelective(book,bookExample);
                session.commit();
            } finally {
                session.close();
            }
        }
    
        @Test
        public void updateByExample() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    
                Book book = new Book(null,"忽略null的列", null, null,1234,124);
                BookExample bookExample = new BookExample();
                bookExample.createCriteria().andIdGreaterThan(8);
                /**
                 * 根据条件来进行更新,而且不带null的列
                 */
                mapper.updateByExample(book,bookExample);
    
                session.commit();
    
            } finally {
                session.close();
            }
        }
    
        @Test
        public void updateByPrimaryKeySelective() {
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
    
                Book book = new Book(null,"忽略null的列", null, null,1234,124);
    
                /**
                 * 根据条件来进行更新,而且不带null的列
                 */
                mapper.updateByPrimaryKeySelective(book);
                session.commit();
    
            } finally {
                session.close();
            }
        }
    
        @Test
        public void updateByPrimaryKey() {
    
            SqlSession session = sqlSessionFactory.openSession();
    
            try {
                BookMapper mapper = session.getMapper(BookMapper.class);
                Book book = new Book(null,"忽略null的列", null, null,1234,124);
    
                /**
                 * 根据条件来进行更新
                 */
                mapper.updateByPrimaryKey(book);
                session.commit();
    
            } finally {
                session.close();
            }
        }
    }
    

    文章持续更新:欢迎各位小伙伴关注我的公众号:菜丸的程序屋。希望将我的不足之处给予指点,谢谢大家。喜欢Java,热衷学习的小伙伴可以加我微信: CaiWan_Y
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 逆向工程入门学习1

    万次阅读 多人点赞 2018-06-03 19:28:40
    逆向工程(一):汇编、逆向工程基础篇VillanCh2015-11-24共883215人围观 ,发现 43 个不明物体周边系统安全本文原创作者:VillanCh本系列文章将讲解逆向工程的各种知识,难度由浅入深。 汇编是逆向工程的基础,...

    逆向工程

    (一):汇编、逆向工程基础篇

    VillanCh2015-11-24883215人围观 ,发现 43 个不明物体周边系统安全

    本文原创作者:VillanCh

    本系列文章将讲解逆向工程的各种知识,难度由浅入深。 

    汇编是逆向工程的基础,这篇文章讲解并不深入但是覆盖了你刚开始学习汇编需要了解的所有基础知识!汇编语言是一切程序的起点和终点,毕竟所有的高级语言都是建立在汇编基础之上的。在许多高级语言中我们都需要相对明确的语法,但是在汇编中,我们会使用一些单词缩写和数字来表达程序。

    I. 单元、位和字节

    ·BIT(位) - 电脑数据量的最小单元,可以是0或者1。
    例:00000001 = 1;00000010 = 2;00000011 = 3     
    ·BYTE(字节) - 一个字节包含8个位,所以一个字节最大值是255(0-255)。为了方便阅读,我们通常使用16进制来表示。
    ·WORD(字) - 一个字由两个字节组成,共有16位。一个字的最大值是0FFFFh (或者是 65535d) (h代表16进制,d代表10进制)。
    ·DOUBLE WORD(双字DWORD) - 一个双字包含两个字,共有32位。最大值为0FFFFFFFF (或者是 4294967295d)。
    ·KILOBYTE(千字) - 千字节并不是1000个字节,而是1024 (32*32) 个字节。
    ·MEGABYTE - 兆字节同样也不是一兆个字节,而是1024*1024=1,048,576 个字节

    II. 寄存器

    寄存器是计算机储存数据的“特别地方”。你可以把寄存器看作一个小盒子,我们可以在里面放很多东西:比如名字、数字、一段话……

    如今Win+Intel CPU组成的计算机通常有9个32位寄存器 (w/o 标志寄存器)。它们是:

    EAX: 累加器
    EBX: 基址寄存器
    ECX: 计数器
    EDX: 数据寄存器
    ESI: 源变址寄存器
    EDI: 目的变址寄存器
    EBP: 扩展基址指针寄存器
    ESP: 栈指针寄存器
    EIP: 指令指针寄存器

    通常来说寄存器大小都是32位 (四个字节) 。它们可以储存值为从0-FFFFFFFF (无符号)的数据。起初大部分寄存器的名字都暗示了它们的功能,比如ECX=计数,但是现在你可以使用任意寄存器进行计数 (只有在一些自定义的部分,计数才必须用到ECX)。当我用到EAX、EBX、ECX、EDX、ESI和EDI这些寄存器时我才会详细解释其功能,所以我们先讲EBP、ESP、EIP。 

    EBP: EBP在栈中运用最广,刚开始没有什么需要特别注意的 ;) 
    ESP: ESP指向栈区域的栈顶位置。栈是一个存放即将会被用到的数据的地方,你可以去搜索一下push/pop 指令了解更多栈知识。 
    EIP: EIP指向下一个将会被执行的指令。

    还有一件值得注意的事:有一些寄存器是16位甚至8位的,它们是不能直接寻址的。

    包括:

    通常一个寄存器可以这样看:

    由图可知,EAX是这个32位寄存器的名字,EAX的低16位部分被称作AX,AX又分为高8位的AH和低8位的AL两个独立寄存器。 

    注意:即使不怎么重要,你至少也要知道以下的寄存器

    这些寄存器可以帮助我们区分大小: 

    i. 单字节(8位)寄存器: 顾名思义,这些寄存器都是一个字节 (8位) :

    AL and AH
    BL and BH
    CL and CH
    DL and DH

    ii. 单字(16位)寄存器: 这些寄存器大小为一个字 (=2 字节 = 16 位)。一个单字寄存器包含两个单字节寄存器。我们通常根据它们的功能来区分它们。 

    1. 通用寄存器:

    AX (单字=16位) = AH + AL -> 其中‘+’号并不代表把它们代数相加。AH和AL寄存器是相互独立的,只不过都是AX寄存器的一部分,所以你改变AH或AL (或者都改变) ,AX寄存器也会被改变。 
    -> 'accumulator'(累加器):用于进行数学运算
    BX -> 'base'(基址寄存器):用来连接栈(之后会说明)
    CX -> 'counter'(计数器):
    DX -> 'data'(数据寄存器):大多数情况下用来存放数据
    DI -> 'destination index'(目的变址寄存器): 例如将一个字符串拷贝到DI
    SI -> 'source index'(源变址寄存器): 例如将一个字符串从SI拷贝

    2. 索引寄存器(指针寄存器): 

    BP -> 'base pointer'(基址指针寄存器):表示栈区域的基地址
    SP -> 'stack pointer'(栈指针寄存器):表示栈区域的栈顶地址

    3. 段寄存器:

    CS -> 'code segment'(代码段寄存器):用于存放应用程序代码所在段的段基址(之后会说明)
    DS -> 'data segment'(数据段寄存器):用于存放数据段的段基址(以后会说明)
    ES -> 'extra segment'(附加段寄存器):用于存放程序使用的附加数据段的基地址
    SS -> 'stack segment'(栈段寄存器):用于存放栈段的段基址(以后会说明)

    4. 指令指针寄存器:

    IP -> 'instruction pointer'(指令指针寄存器):指向下一个指令 ;)

    iii. 双字(32位)寄存器:

    2 字= 4 字节= 32 位, EAX、EBX、ECX、EDX、EDI…… 

    如果16位寄存器前面加了‘E’,就代表它们是32位寄存器。例如,AX=16位,EAX=32位。 

    III. 标志寄存器

    标志寄存器代表某种状态。在32位CPU中有32个不同的标志寄存器,不过不用担心,我们只关心其中的3个:ZF、OF、CF。在逆向工程中,你了解了标志寄存器就能知道程序在这一步是否会跳转,标志寄存器就是一个标志,只能是0或者1,它们决定了是否要执行某个指令。

    Z-Flag(零标志):

    ZF是破解中用得最多的寄存器(通常情况下占了90%),它可以设成0或者1。若上一个运算结果为0,则其值为1,否则其值为0。(你可能会问为什么‘CMP’可以操作ZF寄存器,这是因为该指令在做比较操作(等于、不等于),那什么时候结果是0什么时候是1呢?待会再说) 

    The O-Flag(溢出标志):

    OF寄存器在逆向工程中大概占了4%,当上一步操作改变了某寄存器的最高有效位时,OF寄存器会被设置成1。例如:EAX的值为7FFFFFFFF,如果你此时再给EAX加1,OF寄存器就会被设置成1,因为此时EAX寄存器的最高有效位改变了(你可以使用电脑自带计算器将这个16进制转化成2进制看看)。还有当上一步操作产生溢出时(即算术运算超出了有符号数的表示范围),OF寄存器也会被设置成1。 

    The C-Flag(进位标志):

    进位寄存器的使用大概占了1%,如果产生了溢出,就会被设置成1。例,假如某寄存器值为FFFFFFFF,再加上1就会产生溢出,你可以用电脑自带的计算器尝试。 

    IV. 段偏移 

    内存中的一个段储存了指令(CS)、数据(DS)、堆栈(SS)或者其他段(ES)。每个段都有一个偏移量,在32位应用程序下,这些偏移量由 00000000 到 FFFFFFFF。段和偏移量的标准形式如下:

    段:偏移量 = 把它们放在一起就是内存中一个具体的地址。

    可以这样看:

    一个段是一本书的某一页:偏移量是一页的某一行

    V. 栈

    栈是内存里可以存放稍后会用到的东西的地方。可以把它看作一个箱子里的一摞书,最后一本放进去的永远是最先出来的。或者把栈看作一个放纸的盒子,盒子是栈,而每一张纸就代表了一个内存地址。总之记住这个规则:最后放的纸最先被拿出来。’push’命令就是向栈中压入数据,‘pop’命令就是从栈中取出最后放入的数据并且把它存进具体的寄存器中。

    VI. 指令 (字母表排序) 

    请注意,所有的值通常是以16进制形式储存的。

    大部分指令有两个操作符 (例如:add EAX, EBX),有些是一个操作符 (例如:not EAX),还有一些是三个操作符 (例如:IMUL EAX、EDX、64)。如果你使用 “DWORD PTR [XXX]”就表示使用了内存中偏移量为[XXX]的的数据。注意:字节在内存中储存方式是倒过来的(Win+Intel的电脑上大部分采用”小端法”, WORD PTR [XXX](双字节)和 BYTE PTR [XXX](单字节)也都遵循这一规定)。 

    大部分有两个操作符的指令都是以下这些形式(以add指令举例):

    add eax,ebx                          ;; 寄存器, 寄存器
    add eax,123                          ;; 寄存器, 数值
    add eax,dword ptr [404000]           ;; 寄存器, Dword  指针 [数值]
    add eax,dword ptr [eax]              ;; 寄存器, Dword  指针 [寄存器值]
    add eax,dword ptr [eax+00404000]     ;; 寄存器, Dword  指针 [寄存器值+数值]
    add dword ptr [404000],eax           ;; Dword 指针[数值], 寄存器
    add dword ptr [404000],123           ;; Dword 指针[数值], 数值
    add dword ptr [eax],eax              ;; Dword 指针[寄存器值], 寄存器
    add dword ptr [eax],123              ;; Dword 指针[寄存器值], 数值
    add dword ptr [eax+404000],eax       ;; Dword 指针[寄存器值+数值], 寄存器
    add dword ptr [eax+404000],123       ;; Dword 指针[寄存器值+数值], 数值

    ADD (加)

    语法: ADD 被加数, 加数

    加法指令将一个数值加在一个寄存器上或者一个内存地址上。

    add eax,123 = eax=eax+123;

    加法指令对ZF、OF、CF都会有影响。

    AND (逻辑与)

    语法: AND 目标数, 原数    

    AND运算对两个数进行逻辑与运算。

    AND指令会清空OF,CF标记,设置ZF标记。

    为了更好地理解AND,这里有两个二进制数:

    1001010110
    0101001101

    如果对它们进行AND运算,结果是0001000100

    即同真为真(1),否则为假(0),你可以用计算器验证。

    CALL (调用)

    语法:CALL something

    CALL指令将当前的相对地址(IP)压入栈中,并且调用CALL 后的子程序

    CALL 可以这样使用:

    CALL 404000                ;; 最常见: CALL 地址
    CALL EAX                   ;; CALL 寄存器 - 如果寄存器存的值为404000,那就等同于第一种情况
    CALL DWORD PTR [EAX]       ;; CALL [EAX]偏移量所指向的地址
    CALL DWORD PTR [EAX+5]     ;; CALL [EAX+5]偏移量所指向的地址

    CDQ

    Syntax: CDQ

    CDQ指令第一次出现时通常不好理解。它通常出现在除法前面,作用是将EDX的所有位变成EAX最高位的值,

    比如当EAX>=80000000h时,其二进制最高位为1,则EDX被32位全赋值为1,即FFFFFFFF

    若EAX<80000000,则其二进制最高位为0,EDX为00000000。

    然后将EDX:EAX组成新数(64位):FFFFFFFF 80000000

    CMP (比较)

    语法: CMP 目标数, 原数

    CMP指令比较两个值并且标记CF、OF、ZF:

    CMP     EAX, EBX              ;; 比较eax和ebx是否相等,如果相等就设置ZF为1
    CMP     EAX,[404000]          ;; 比较eax和偏移量为[404000]的值是否相等
    CMP     [404000],EAX          ;; 比较[404000]是否与eax相等

    DEC (自减)

    语法: DEC something

    dec用来自减1,相当于c中的–

    dec可以有以下使用方式:

    dec eax                             ;; eax自减1
    dec [eax]                           ;; 偏移量为eax的值自减1
    dec [401000]                        ;; 偏移量为401000的值自减1
    dec [eax+401000]                    ;; 偏移量为eax+401000的值自减1

    dec指令可以标记ZF、OF

    DIV (除)

    语法: DIV 除数

    DIV指令用来将EAX除以除数(无符号除法),被除数通常是EAX,结果也储存在EAX中,而被除数对除数取的模存在除数中。

    例:

    mov eax,64                      ;; EAX = 64h = 100
    mov ecx,9                       ;; ECX = 9
    div ecx                         ;; EAX除以ECX

    在除法之后 EAX = 100/9 = 0B(十进制:11) 并且 ECX = 100 MOD 9 = 1

    div指令可以标记CF、OF、ZF

    IDIV (整除)

    语法: IDIV 除数

    IDIV执行方式同div一样,不过IDIV是有符号的除法

    idiv指令可以标记CF、OC、ZF

    IMUL (整乘)

    语法:IMUL 数值

    IMUL 目标寄存器、数值、数值

    IMUL 目标寄存器、数值

    IMUL指令可以把让EAX乘上一个数(INUL 数值)或者让两个数值相乘并把乘积放在目标寄存器中(IMUL 目标寄存器, 数值,数值)或者将目标寄存器乘上某数值(IMUL 目标寄存器, 数值)

    如果乘积太大目标寄存器装不下,那OF、CF都会被标记,ZF也会被标记

    INC (自加)

    语法: INC something

    INC同DEC相反,它是将值加1

    INC指令可以标记ZF、OF

    INT

    语法: int 目标数

    INT 的目标数必须是产生一个整数(例如:int 21h),类似于call调用函数,INT指令是调用程序对硬件控制,不同的值对应着不同的功能。

    具体参照硬件说明书。

    JUMPS

    这些都是最重要的跳转指令和触发条件(重要用*标记,最重要用**标记):

    指令                条件                    条件
    JA*          -    如果大于就跳转(无符号)      - CF=0 and ZF=0
    JAE          -    如果大于或等于就跳转(无符号)- CF=0
    JB*          -    如果小于就跳转(无符号)   - CF=1
    JBE          -    如果小于或等于就跳转(无符号)- CF=1 or ZF=1
    JC           -    如果CF被标记就了跳转       - CF=1
    JCXZ         -    如果CX等于0就跳转      - CX=0
    JE**         -    如果相等就跳转        - ZF=1
    JECXZ        -    如果ECX等于0就跳转       - ECX=0
    JG*          -    如果大于就跳转(有符号)   - ZF=0 and SF=OF (SF = Sign Flag)
    JGE*         -    如果大于或等于就跳转(有符号) - SF=OF
    JL*          -    如果小于就跳转(有符号)    - SF != OF (!= is not)
    JLE*         -    如果小于或等于就跳转(有符号 - ZF=1 and OF != OF
    JMP**        -    跳转             - 强制跳转
    JNA          -    如果不大于就跳转(无符号)   - CF=1 or ZF=1
    JNAE         -    如果不大于等于就跳转(无符号) - CF=1
    JNB          -    如果不小于就跳转(无符号)   - CF=0
    JNBE         -    如果不小于等于就跳转(无符号) - CF=0 and ZF=0
    JNC          -    如果CF未被标记就跳转     - CF=0
    JNE**        -    如果不等于就跳转       - ZF=0
    JNG          -    如果不大于就跳转(有符号)   - ZF=1 or SF!=OF
    JNGE         -    如果不大于等于就跳转(有符号) - SF!=OF
    JNL          -    如果不小于就跳转(有符号)   - SF=OF
    JNLE         -    如果不小于等于就跳转(有符号) - ZF=0 and SF=OF
    JNO          -    如果OF未被标记就跳转     - OF=0
    JNP          -    如果PF未被标记就跳转     - PF=0
    JNS          -    如果SF未被标记就跳转      - SF=0
    JNZ          -    如果不等于0就跳转      - ZF=0
    JO           -    如果OF被标记就跳转     - OF=1
    JP           -    如果PF被标记就跳转     - PF=1
    JPE          -    如果是偶数就跳转       - PF=1
    JPO          -    如果是奇数就跳转       - PF=0
    JS           -    如果SF被标记就跳转     - SF=1
    JZ           -    如果等于0就跳转      - ZF=1

    LEA (有效地址传送)

    语法:LEA 目的数、源数

    LEA可以看成和MOV差不多的指令LEA ,它本身的功能并没有被太广泛的使用,反而广泛运用在快速乘法中:

    lea eax,dword ptr [4*ecx+ebx]

    将eax赋值为 4*ecx+ebx

    MOV (传送)

    语法: MOV 目的数,源数

    这是一个很简单的指令,MOV指令将源数赋值给目的数,并且源数值保持不变

    这里有一些MOV的变形:

    MOVS/MOVSB/MOVSW/MOVSD EDI, ESI:这些变形能将ESI指向的内容传送到EDI指向的内容中去

    MOVSX:MOVSX指令将单字或者单字节扩展为双字或者双字节传送,原符号不变

    MOVZX:MOVZX扩展单字节或单字为双字节或双字并且用0填充剩余部分(通俗来说就是将源数取出置于目的数,其他位用0填充)

    MUL (乘法)

    语法:MUL 数值

    这个指令同IMUL一样,不过MUL可以乘无符号数。

    NOP (无操作)

    语法:NOP

    这个指令说明不做任何事

    所以它在逆向中运用范围最广

    OR (逻辑或)

    语法:OR 目的数,源数

    OR指令对两个值进行逻辑或运算

    这个指令会清空OF、CF标记,设置ZF标记

    为了更好的理解OR,思考下面二进制串:

    1001010110
    0101001101

    如果对它们进行逻辑与运算,结果将是1101011111。

    只有当两边同为0时其结果为0,否则就为1。你可以用计算器尝试计算。希望你能理解为什么,最好自己动手算一算

    POP

    语法:POP 目的地址

    POP指令将栈顶第一个字传送到目的地址。 每次POP后,ESP(栈指针寄存器)都会增加以指向新栈顶

    PUSH

    语法:PUSH 值

    PUSH是POP的相反操作,它将一个值压入栈并且减小栈顶指针值以指向新栈顶。

    REP/REPE/REPZ/REPNE/REPNZ

    语法: REP/REPE/REPZ/REPNE/REPNZ ins

    重复上面的指令:直到CX=0。ins必须是一个操作符,比如CMPS、INS、LODS、MOVS、OUTS、SCAS 或 STOS

    RET (返回)

    语法:RET

    RET digit

    RET指令的功能是从一个代码区域中退出到调用CALL的指令处。

    RET digit在返回前会清理栈

    SUB (减)

    语法:SUB 目的数,源数

    SUB与ADD相反,它将源数减去目的数,并将结果储存在目的数中

    SUB可以标记ZF、OF、CF

    TEST

    语法:TEST 操作符、操作符

    这个指令99%都是用于”TEST EAX, EAX”,它执行与AND相同的功能,但是并不储存数据。如果EAX=0就会标记ZF,如果EAX不是0,就会清空ZF

    XOR

    语法:XOR 目的数,源数

    XOR指令对两个数进行异或操作

    这个指令清空OF、CF,但会标记ZF

    为了更好的理解,思考下面的二进制串:

    1001010110
    0101001101

    如果异或它们,结果将是1100011011

    如果两个值相等,则结果为0,否则为1,你可以使用计算器验算。

    很多情况下我们会使用”XOR EAX, EAX”,这个操作是将EAX赋值为0,因为当一个值异或其自身,就过都是0。你最好自己动手尝试下,这样可以帮助你理解得更好。

    VII. 逻辑操作符  

    下面都是通常的逻辑操作符:















    逆向工程(二):从一个简单的实例来了解PE文件



    文中RegisterMe及原视频下载地址:http://pan.baidu.com/s/1bnqOgnt打开这个RegisterMe.exe程序,会出现如下烦人的消息框:

    引入

    目标:去掉烦人的消息框

    工具:Ollydbg

    1.载入程序,由图可以看出调用了两个MessageBox,当程序执行到这里的时候分别会有上述消息框弹出。 

    2.观察 cmp eax,0×0

    这里判断eax是否等于0

    je(如果相等就跳转 – ZF=1  

    由于eax等于40000

    所以这一个跳转永远不会成立,所以一定会执行这个烦人的MessageBox。

    那么我们就可以想办法使它跳转。

    3.我们尝试改变ZF标记值(je跳转根据ZF标记判断)

    如图,此时ZF标记为0,我们双击这个0,使其标记为1

    再观察:

    跳转实现了,我们成功跳过了消息窗口!!

    不过这样每次要改变ZF标记很麻烦,我们可不可以让它直接跳转不进行判断呢?所以我们可以双击编辑je short 00401024为jmp short 00401024

    成功跳过了MessageBox!!

    我们想使用一种更加完美的方法来跳过这个消息框。。。。

    假如我们把程序入口设置成00401024不就直接跳过了MessageBox了吗?在这之前,我需要解释一些PE的知识(请耐心地阅读,这才是本文所要讲的重点,而不是如何破解这个程序!!) 

    下面标有红色的代表重点,如果你时间紧迫,可以只看有下划线的文字

    深入的必经之路:

    PE(Portable Executable)文件简介

    PE(Portable Executable)文件是Windows操作系统下使用的可执行文件格式。它是微软在UNIX平台的COFF(通用对象文件格式)基础上制作而成。最初设计用来提高程序在不同操作系统上的移植性,但实际上这种文件格式仅用在Windows系列操作系统下。

    PE文件是指32位可执行文件,也称为PE32。64位的可执行文件称为PE+或PE32+,是PE(PE32)的一种扩展形式(请注意不是PE64)。

    PE文件结构一般如上图所示。

    当一个PE文件被执行时,PE装载器首先检查DOS header里的PE header的偏移量。如果找到,则直接跳转到PE header的位置。

    当PE装载器跳转到PE header后,第二步要做的就是检查PE header是否有效。如果该PE header有效,就跳转到PE header的尾部。

    紧跟PE header尾部的是节表。PE装载器执行完第二步后开始读取节表中的节段信息,并采用文件映射(在执行一个PE文件的时候,Windows并不在一开始就将整个文件读入内存,而是采用与内存映射的机制,也就是说,Windows装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页中的指令或者访问某一页中的数据时,这个页面才会被从磁盘提交到物理内存,这种机制使文件装入的速度和文件大小没有太大的关系)的方法将这些节段映射到内存,同时附上节表里指定节段的读写属性。

    PE文件映射入内存后,PE装载器将继续处理PE文件中类似 import table (输入表)的逻辑部分

    这四个步骤便是PE文件的执行顺序,具体细节读者可以参考相关文档。

    (以上四个步骤摘自《黑客破解精通》) 

    下面用我们要破解程序进行简单说明:

    首先用WinHex 打开破解程序。上图是程序的起始部分,也是PE文件的头部分。文件运行需要的所有信息就储存在这个PE头文件中。所以,学习PE文件格式就是学习PE头中的结构体。

     

    事情根本没有这么简单:

    上图描述了文件加载到内存的情形,包含了许多内容,我们逐一学习。

    文件中使用偏移(offset),内存中使用VA(Virtual Address,虚拟地址)来表示位置。

    VA指进程虚拟内存的绝对地址,RVA(Relative Virtual Address,相对虚拟地址)是指从某基准位置(ImageBase)开始的相对地址。VA与RVA满足下面的换算关系:

    RVA+ImageBase=VA

    PE头内部信息大多是RVA形式存在。原因在于(主要是DLL)加载到进程虚拟内存的特定位置时,该位置可能已经加载了其他的PE文件(DLL)。此时必须通过重定向(Relocation)将其加载到其他空白的位置,若PE头信息使用的是VA,则无法正常访问。因此使用RVA来重定向信息,即使发生了重定向,只要相对于基准位置的相对位置没有变化,就能正常访问到指定信息,不会出现任何问题。

    当PE文件被执行时,PE装载器会为进程分配4CG的虚拟地址空间,然后把程序所占用的磁盘空间作为虚拟内存映射到这个4GB的虚拟地址空间中。一般情况下,会映射到虚拟地址空间中的0X400000的位置。

    PE头:

    DOS头

    typedef struct _IMAGE_DOS_HEADER { // DOS的.EXE头部
      USHORT e_magic; // DOS签名“MZ-->Mark Zbikowski(设计了DOS的工程师)”
      USHORT e_cblp; // 文件最后页的字节数
      USHORT e_cp; // 文件页数
      USHORT e_crlc; // 重定义元素个数
      USHORT e_cparhdr; // 头部尺寸,以段落为单位
      USHORT e_minalloc; // 所需的最小附加段
      USHORT e_maxalloc; // 所需的最大附加段
      USHORT e_ss; // 初始的SS值(相对偏移量)
      USHORT e_sp; // 初始的SP值
      USHORT e_csum; // 校验和
      USHORT e_ip; // 初始的IP值
      USHORT e_cs; // 初始的CS值(相对偏移量)
      USHORT e_lfarlc; // 重分配表文件地址
      USHORT e_ovno; // 覆盖号
      USHORT e_res[4]; // 保留字
      USHORT e_oemid; // OEM标识符(相对e_oeminfo)
      USHORT e_oeminfo; // OEM信息
      USHORT e_res2[10]; // 保留字
      LONG e_lfanew; // 指示NT头的偏移(根据不同文件拥有可变值)
    } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    其中比较重要的有e_magic和e_lfanew,由图可知

    e_magic的值为4D5A,e_lfanew的值为000000C0(注意不是C0000000,详见我的上一篇文章)

    WORD占2个字节,LONG占4个字节,刚好是30个WORD和1个LONG,从00000000到0000003F 

    DOS存根:

    即使没有DOS存根,文件也能正常执行

    NT头(PE最重要的头):

    其定义如下:

    typedef struct _IMAGE_NT_HEADERS { 
            DWORD Signature; 
            IMAGE_FILE_HEADER FileHeader; 
            IMAGE_OPTIONAL_HEADER32 OptionalHeader; 
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;  
     
    Signature:类似于DOS头中的e_magic,其高16位是0,低160x4550,用字符表示是&#039;PE‘(00004550)。
    IMAGE_FILE_HEADERIMAGE_FILE_HEADERPE文件头,定义如下:
        typedef struct _IMAGE_FILE_HEADER { 
            WORD    Machine; 
            WORD    NumberOfSections; 
            DWORD   TimeDateStamp; 
            DWORD   PointerToSymbolTable; 
            DWORD   NumberOfSymbols; 
            WORD    SizeOfOptionalHeader; 
            WORD    Characteristics; 
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

     

    其中有4个重要的成员(若设置不正确,将会导致文件无法正常运行)

    #1.Machine

    每个CPU拥有唯一的Machine码,兼容32位Intel X86芯片的Machine码为14C(如图)。以下是定义在winnt.h文件中的Machine码:

    #define IMAGE_FILE_MACHINE_UNKNOWN           0 
        #define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386. 
        #define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian 
        #define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian 
        #define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian 
        #define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2 
        #define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP 
        #define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian 
        #define IMAGE_FILE_MACHINE_SH3DSP            0x01a3 
        #define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian 
        #define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian 
        #define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5 
        #define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian 
        #define IMAGE_FILE_MACHINE_THUMB             0x01c2 
        #define IMAGE_FILE_MACHINE_AM33              0x01d3 
        #define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian 
        #define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1 
        #define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64 
        #define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS 
        #define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64 
        #define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS 
        #define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS 
        #define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64 
        #define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon 
        #define IMAGE_FILE_MACHINE_CEF               0x0CEF 
        #define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code 
        #define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8) 
        #define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
        #define IMAGE_FILE_MACHINE_CEE               0xC0EE

    #2.NumberOfEsctions

    PE文件把代码,数据,资源等依据属性分类到各节中储存。

    NumberOfEsctions指文件中存在的节段(又称节区)数量,也就是节表中的项数。该值一定要大于0,且当定义的节段数与实际不符时,将发生运行错误。

    #3.SizeOfOptionalHeader

    IMAGE_NT_HEADERS结构最后一个成员IMAGE_OPTIONAL_HEADER32。

    SizeOfOptionalHeader用来指出IMAGE_OPTIONAL_HEADER32结构体的长度。PE装载器需要查看SizeOfOptionalHeader的值,从而识别IMAGE_OPTIONAL_HEADER32结构体的大小。

    PE32+格式文件中使用的是IMAGE_OPTIONAL_HEADER64结构体,这两个结构体尺寸是不相同的,所以需要在SizeOfOptionalHeader中指明大小。

    #4.Characteristics

    该段用于标识文件的属性,文件是否是可运行的状态,是否为DLL文件等信息。

    #define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file. 
        #define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references). 
        #define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file. 
        #define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file. 
        #define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set 
        #define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses 
        #define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed. 
        #define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine. 
        #define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file 
        #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file. 
        #define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file. 
        #define IMAGE_FILE_SYSTEM                    0x1000  // System File. 
        #define IMAGE_FILE_DLL                       0x2000  // File is a DLL. 
        #define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine 
        #define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

    为方便理解,上述程序的NT头内容如下:

    (成员功能概述)

    NumberOfSections:该PE文件中有多少个节段,也就是节表中的项数。
    TimeDateStampPE文件的创建时间,一般有连接器填写。
    PointerToSymbolTableCOFF文件符号表在文件中的偏移。
    NumberOfSymbols:符号表的数量。
    SizeOfOptionalHeader:紧随其后的可选头的大小。
    Characteristics:可执行文件的属性。

    IMAGE_OPTIONAL_HEADER32:

    其定义如下: 

    typedef struct _IMAGE_OPTIONAL_HEADER { 
            WORD    Magic; 
            BYTE    MajorLinkerVersion; 
            BYTE    MinorLinkerVersion; 
            DWORD   SizeOfCode; 
            DWORD   SizeOfInitializedData; 
            DWORD   SizeOfUninitializedData; 
            DWORD   AddressOfEntryPoint; 
            DWORD   BaseOfCode; 
            DWORD   BaseOfData; 
            DWORD   ImageBase; 
            DWORD   SectionAlignment; 
            DWORD   FileAlignment; 
            WORD    MajorOperatingSystemVersion; 
            WORD    MinorOperatingSystemVersion; 
            WORD    MajorImageVersion; 
            WORD    MinorImageVersion; 
            WORD    MajorSubsystemVersion; 
            WORD    MinorSubsystemVersion; 
            DWORD   Win32VersionValue; 
            DWORD   SizeOfImage; 
            DWORD   SizeOfHeaders; 
            DWORD   CheckSum; 
            WORD    Subsystem; 
            WORD    DllCharacteristics; 
            DWORD   SizeOfStackReserve; 
            DWORD   SizeOfStackCommit; 
            DWORD   SizeOfHeapReserve; 
            DWORD   SizeOfHeapCommit; 
            DWORD   LoaderFlags; 
            DWORD   NumberOfRvaAndSizes; 
            IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 
        } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

     

    我们需要关注下列成员,这些事运行程序必需的,设置错误将导致程序无法正常运行。

    #1.Magic

    为IMAGE_OPTIONAL_HEADER32时,magic码为10B,为IMAGE_OPTIONAL_HEADER64时,magic码为20B

    #2.AddressOfEntryPoint

    AddressOfEntryPoint持有EP的RVA值。该值指出程序最先执行的代码起始地址,相当重要。

    #3.ImageBase

    一般来说,使用开发工具(VB/VC++/Delphi)创建好EXE文件后,其ImageBase值为00400000,DLL文件的ImageBase值为10000000(当然也可以指定其他值)。

    执行PE文件时,PE装载器先创建进程,再将文件载入内存,然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint

    #4.SectionAlignment,FileAlignment

    PE文件的Body部分被划分成若干节段,这些节段储存着不同类别的数据。FileAlignment指定了节段在磁盘文件中的最小单位,而SectionAlignment则指定了节区在内存中的最小单位(SectionAlignment必须大于或者等于FileAlignment)

    #5.SizeOfImage

    当PE文件加载到内存时,SizeOfImage指定了PE Image在虚拟内存中所占用的空间大小,一般文件大小与加载到内存中的大小是不同的(节段头中定义了各节装载的位置与占有内存的大小,后面会讲到)

    #6.SizeOfHeader

    SizeOfHeader用来指出整个PE头大小。该值必须是FileAlignment的整数倍。第一节段所在位置与SizeOfHeader距文件开始偏移的量相同。

    #7.Subsystem

    Subsystem值用来区分系统驱动文件(*.sys)与普通可执行文件(*.exe,*.dll)。

    Subsystem成员可拥有值如下:

    #define IMAGE_SUBSYSTEM_UNKNOWN              0   // Unknown subsystem.  
    #define IMAGE_SUBSYSTEM_NATIVE               1   // Image doesn&#039;t require a subsystem.   系统驱动
    #define IMAGE_SUBSYSTEM_WINDOWS_GUI          2   // Image runs in the Windows GUI subsystem.  窗口应用程序
    #define IMAGE_SUBSYSTEM_WINDOWS_CUI          3   // Image runs in the Windows character subsystem.  控制台应用程序
    #define IMAGE_SUBSYSTEM_OS2_CUI              5   // image runs in the OS/2 character subsystem.  
    #define IMAGE_SUBSYSTEM_POSIX_CUI            7   // image runs in the Posix character subsystem.  
    #define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8   // image is a native Win9x driver.  
    #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9   // Image runs in the Windows CE subsystem.  
    #define IMAGE_SUBSYSTEM_EFI_APPLICATION      10  //  
    #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11   //  
    #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER   12  //  
    #define IMAGE_SUBSYSTEM_EFI_ROM              13  
    #define IMAGE_SUBSYSTEM_XBOX                 14  
    #define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16

    #8.DataDirectory

    数据目录,定义如下:

    ·  typedef struct _IMAGE_DATA_DIRECTORY {  
    ·      DWORD   VirtualAddress;  
    ·      DWORD   Size;  
    ·  } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

    可以看出,有地址(VirtualAddress)有大小(Size),数组定义的一定是一个区域,数组每项都有被定义的值,不同项对应不同数据结构,比如导入表,导出表等,定义如下:

    #define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory 
    #define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory 
    #define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory 
    #define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory 
    #define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory 
    #define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table 
    #define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory 
    //      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage) 
    #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data 
    #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP 
    #define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory 
    #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory 
    #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers 
    #define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table 
    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors 
    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

    各位重点关注标红的IMPORT和EXPORT,它们是PE头中的非常重要的部分,其它部分不怎么重要,大致了解下即可。 

    #9.NumberOfRvaAndSizes

    NumberOfRvaAndSizes用来指定DataDirectory的数组个数,虽然结构体定义中明确指出了数组个数为16,但也有可能不是16,PE装载器需要通过这个值来识别。

    各成员代表的值和偏移量就不一一写出了,累死咯。。。 

    (成员功能概述)

    Magic:表示可选头的类型。
    MajorLinkerVersion和MinorLinkerVersion:链接器的版本号。
    SizeOfCode:代码段的长度,如果有多个代码段,则是代码段长度的总和。
    SizeOfInitializedData:初始化的数据长度。
    SizeOfUninitializedData:未初始化的数据长度。
    AddressOfEntryPoint:程序入口的RVA,对于exe这个地址可以理解为WinMain的RVA。对于DLL,这个地址可以理解为DllMain的RVA,如果是驱动程序,可以理解为DriverEntry的RVA。当然,实际上入口点并非是WinMain,DllMain和DriverEntry,在这些函数之前还有一系列初始化要完成,当然,这些不是本文的重点。
    BaseOfCode:代码段起始地址的RVA。
    BaseOfData:数据段起始地址的RVA。
    ImageBase:映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。
    SectionAlignment:节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0。
    FileAlignment:节在文件中按此值对齐,SectionAlignment必须大于或等于FileAlignment。
    MajorOperatingSystemVersion、MinorOperatingSystemVersion:所需操作系统的版本号,随着操作系统版本越来越多,这个好像不是那么重要了。
    MajorImageVersion、MinorImageVersion:映象的版本号,这个是开发者自己指定的,由连接器填写。
    MajorSubsystemVersion、MinorSubsystemVersion:所需子系统版本号。
    Win32VersionValue:保留,必须为0。
    SizeOfImage:映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小。
    SizeOfHeaders:所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的。
    CheckSum:映象文件的校验和。
    Subsystem:运行该PE文件所需的子系统。

    DllCharacteristics:DLL的文件属性,只对DLL文件有效,可以是下面定义中某些的组合:

    SizeOfStackReserve:运行时为每个线程栈保留内存的大小。
    SizeOfStackCommit:运行时每个线程栈初始占用内存大小。
    SizeOfHeapReserve:运行时为进程堆保留内存大小。
    SizeOfHeapCommit:运行时进程堆初始占用内存大小。
    LoaderFlags:保留,必须为0。
    NumberOfRvaAndSizes:数据目录的项数,即下面这个数组的项数。
    DataDirectory:数据目录,这是一个数组。

    节段(区)头:

    PE文件有不同的节段:code(代码),data(数据),resource(资源),这样设计避免了很多安全问题,比如向data写数据,由于某原因导致溢出,其下的code就会被覆盖,程序就会崩溃。

    code/data/resource都有不同的权限,如下:

    节段头是由IMAGE_SECTION_HEADER结构体组成的数组,每个结构体对应一个节段。

    typedef struct _IMAGE_SECTION_HEADER {
      BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
      union {
        DWORD PhysicalAddress;
        DWORD VirtualSize;
      } Misc;
      DWORD VirtualAddress;
      DWORD SizeOfRawData;
      DWORD PointerToRawData;
      DWORD PointerToRelocations;
      DWORD PointerToLinenumbers;
      WORD  NumberOfRelocations;
      WORD  NumberOfLinenumbers;
      DWORD Characteristics;
    } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

    下表列出了需要了解的重要成员:

    VirtualAddress与PointerToRawData不带有任何值,分别由(定义在IMAGE_OPTIONAL_HEADER32中的)SectionAlignment和FileAlignment确定。

    上述程序有4个节段。

    如何运用我们上面学习到的PE知识?

    了解了PE知识,继续我们的破解工作!!

    我们在数据窗口(dump)有点选择跳转,跳转到起始位置(400000):

    点击OK

    我们成功跳转到了起始位置。

    点击右上方LEMTW的M查看内存情况。

    双击该处进入,看到DOS HEADER已经载入了,直接向下翻,查找DOS头的e_lfanew成员:

    查看到偏移量是000000C0,记住我们载入内存时,基准位置(ImageBase)是400000,相对虚拟地址(RVA)是:

    RVA=ImageBase+VA

    所以此时PE头位置是004000C0,我们向下翻到该处。

    开始找最重要的的AddressOfEntryPoint

    找到AddressOfEntryPoint=0×1000,我么需要让它跳转到401024:

    那我们修改其值,双击004000E9(00 10 00 00 –>00001000)的值进行修改,修改为24 10 00 00 (00001024):


    然后保存到可执行文件:


    保存完成后,用OD载入刚保存的RegisterMe1.0,发现入口已经变成了我们修改的00401024,成果跳过了第一个烦人的消息框!

    我们再向下执行:

    执行到call Register.00401052时弹出了“我们需要注册的信息”

    我们再向下执行:

    再第二个MessageBox处又弹出了消息框,我们这次采用NOP(No operation)填充:

    填充完成后,我们保存为可执行文件RegisterMe2.0。双击执行,再也没有可恶地消息框咯!

    *原创作者:VillanCh,本文属FreeBuf原创奖励计划文章,未经作者本人及FreeBuf许可,切勿私自转载

    这些评论亮了

    • 我现在的内心大概是这个样子

      觉得跳跃有点大啊,还是我基础太差了。










    逆向工程(三):实例破解

    VillanCh2015-12-02346669人围观 ,发现 20 个不明物体系统安全

    本文原创作者:VillanCh

    本系列文章将讲解逆向工程的各种知识,难度由浅入深。 

    补课:《逆向工程(一):汇编、逆向工程基础篇》《逆向工程(二):从一个简单的实例来了解PE文件》

    这次我们将破解一款真正的商业程序。

    为了避免一些不必要的麻烦,选择的这款商业程序在2001年就停止维护了,所以我们可以放心大胆的破解学习!

    (不要在这里灰心,即便是2001年的软件,仍有我们值得学习的地方!!)

    这个软件也许我们在有些地方看过,很多教程都喜欢拿这个软件做靶子,但是我们还是要努力玩出一点花样,对不对,简简单单的破解当然学到的不会太多。

    文中软件及原视频下载地址 密码: x3tv

    无壳的实例

    目标:破解软件功能限制

    工具:OD

    安装好这款软件打开如图:

    这款软件有诸多功能限制,如:

    当我们选择Add Group,提示没有注册只能创建3个Group:

    选择Add,提示没有注册只能添加4个联系人:

    我们打开About PixtopianBook,弹出未注册版本信息。

    我们将其载入OD(建议下载一个原版OD#www.ollydbg.de#,我们尝试手动配置忽略异常)如图:

    点击运行后,并没有出现程序界面,而是抛出了异常:

    我们手动开启忽略异常:

    打开后选择 exception:

    勾选如上,再点击Add lase exception。

    配置完成后点击OK。

    配置完成后重新载入程序,点击运行,成功打开了程序。

    正式开始!

    1、Group

    将软件载入OD,点击Add Group。

    我们在其弹出消息框后暂停OD。

    此时状态栏显示:暂停,我们此时需要返回到程序领空,快捷键Alt+F9。

    然后点击消息框 确定 此时状态栏显示:返回到用户

    我们成功返回到程序领空,向上翻。

    看到了一个MessageBox,这就是我们刚才确定的那个消息框。

    向下我们将

    这个命令将带我们返回到调用CALL处。所以我们继续向下执行。

    进行retn:

    我们跳出了call,返回到了调用处、

    我们看到:

    1.这个Call就是我们刚才进入的Call,加入我们能跳过这个call,就能避免跳出消息框。

    2.查看这个ascii码,正是消息框的标题和内容,在这里被压入栈,等待调用。

    3.这里有一个cmp,比较eax与3大小(即Group是否等于3),如果小于就跳转到(JL)00408B34,如果已经有3个Group了,就执行call弹出未注册消息框。

    你一定已经知道我们将要干什么了!

    将JL(小于则跳转)改为jmp(强制跳转)。

    这样我们就成功跳过了GROUP验证。

    我们将其保存:

    测试一下:

    哈哈,已经可以自由添加Group了!!是不是很有成就感啊!学习逆向成就感很重要哦。

    2、联系人

    默认未注册用户只能添加四个联系人,我们采取同样方法:

    1、弹出消息框后暂停

    2、Alt+F9执行到用户代码

    3、点击确定

    跳转到这个位置,我们向上翻,看到同样的MessageBox,如下:

    通过retn跳出call,回到调用处,向上翻:

    1、这个call调用了MessageBox,弹出了消息框;

    2、这句话同我们看到的一样,确定程序在这里将其压入栈;

    3、比较eax与4的大小(联系人是否已经有4个),如果小于等于(JL)4个,那就跳过消息框,否则弹出未注册消息框。

    我们同样修改jl为jmp,强制其跳转:

    保存后测试一下:

    我们又成功搞定了一个功能!这个阉割版已经成了注册版,不过还有一些美中不足的地方。比如:

    那我们就开始让它从里到外都是注册版!

    3、更改版本信息

    标题,版本文字在代码区是找不到的,我们直接在内存中找

    输入查找关键字UNREGISTERED:

    如果ASCII没有搜索到就用UNICODE

    (这里ASCII也可以搜索到,不过不是版本信息,UNICODE下搜索到版本信息,点击确定):

    记录下004D4830,在dump面板跳转:

    跳转之后成功找到需要修改的内容:

    我们选择要修改的内容,右键编辑:

    编辑为自己想写的字符,如下:

    4、DIY标题

    同样是在内存中查找,在弹出的搜索框里输入关键字:(UNREGISTERED VER

    (一般情况下是不知道要搜索的文字是ascii还是unicode,我们会都尝试搜索一次。


    记下004E4BE6,在dump窗口跟随:

    找到需要修改的字符然后编辑:

    确定后如下图所示:

    5、更改提示注册文字

    同理,我们在内存中搜索:

    首先尝试UNICODE,没有搜索到结果。

    再尝试ASCII搜索:

    成功搜到了字符串:

    记录下位置48F974,并跳转到该处:

    用同样的方法编辑ASCII码:

    编辑完成后如下:

    在所有工作做完之后,不要忘记保存:

    保存后我们查看效果:

    6、结尾

    我们仍发现了一些美中不足的地方。

    在进入程序时,首先是欢迎信息:


    几秒后变为:

    我们想让它更加简洁,一直显示welcome信息,该怎么操作呢?

    那我们开始进行最后一步!!

    通过上面的操作我们已经知道了注册文字在48F974处,在dump(数据窗口)窗口右键跳转到48F974

    我们需要知道程序哪一段调用了这段字符串。

    我们右键选择查找参考(Ctrl+R)(个人觉得做汉化翻译得有点问题,这个命令的英文是Find references,意思应该是查找引用,参考这个词不太合适):

    找到一处引用,我们双击进入:

    我们来到如图所示的代码位置:

    发现上面有一处cmp和jnz(cmp与jnz组合代表:如果不相等,则跳转),如果ebp等于907,则将这串字符压入栈(可以猜测,907代表未注册),我们根据跳转向上翻:

    向上翻到这里:

    又有一处cmp和jnz,意思是如果ebp不等于906,就要跳转回0040C22F处。

    (我们可以猜测,906代表注册过)

    这个程序我们已经完全弄清楚了,我们直接在0040C235的jnz处进行强制跳转,让其不会将这串字符压入栈:

    修改后,我们最后一次保存:

    打开:

    整款软件已经被我们完全破解了!!

    虽然这是一款2001年的软件,但这是我们破解的第一款真正的软件!所以今晚好好庆祝一下吧,我们在下一篇教程里再见!!

    *原创作者:VillanCh,本文属FreeBuf原创奖励计划文章,未经作者本人及FreeBuf许可,切勿私自转载

    这些评论亮了

    • ETenal回复
      链接如下:http://yun.baidu.com/s/1eQAuQ6A
    展开全文
  • 逆向工程入门

    万次阅读 多人点赞 2015-07-20 20:13:58
    本问只是为初入逆向工程大坑的新人们指出方向学习,没有实质性的技术。总的来说,基础才是最重要的。逆向工程入门应该算是所有学习方向中最难的。但是选择了这一方向的请不要放弃,一旦学成,必定会是大神级别的存在...

    本问只是为初入逆向工程大坑的新人们指出方向学习,没有实质性的技术。总的来说,基础才是最重要的。

    逆向工程入门应该算是所有学习方向中最难的。但是选择了这一方向的请不要放弃,一旦学成,必定会是大神级别的存在。
    那么,逆向工程的入门需要学习什么?

    1.c语言

    学习c语言是逆向工程的基础。如果是学习渗透方向的,也许可以选择python作为自己的第一门编程语言。但是作为逆向工程方向,第一门入门的语言没有选择,只有c语音。深厚的c语言功底是逆向工程的基础。如果想学习逆向工程,务必要有深厚的c语言功底。逆向工程中c和汇编就是好比是一颗树的根部和树干。没有扎实的基础是无法继续更加深入的学习的。
    ======> 推荐书籍:《c primer plus》业界经典

    2.汇编语言

    作为逆向工程的2大基础语言。汇编语言也是一切其他学习的基础。如果你认为已经具有深厚的c语言功底。可以清楚的理解指针的指针,数组指针,指向数组的指针,函数指针等等指针的概念之后,就可以开始学习汇编语言的。汇编语言是一门很非人类的语言,因为汇编语言其实就是非人类的二进制机器语言的另外一种表达形式而已。但是学习逆向工程,你就无法逃避学习汇编语言。

    学习汇编语言,其实不只是入门而已。汇编语言是需要不断学习研究的。可以按照一下的路线学习

    a.16位汇编
    16位汇编语言可是老古董了。不过作为初始汇编的人来说还是很合适学习的。 =====> 推荐书籍:王爽的《汇编语言》经典必看

    b.32位汇编
    intel x86指令集的32位汇编是现在最主流的指令集了。它继承了16位的汇编指令并发展而来,是现在最主流的汇编语言了。 ======> 推荐书籍:钱晓捷的《基于Windows环境的汇编语言程序设计》个人感觉继续学习32位汇编不错的一本书。

    32位汇编语言学习完成之后,就已经是算汇编,或者是逆向工程入门了。如果希望继续学习汇编,可以从以下方向中自由选择。
    1.64位汇编语言。
    32位汇编再进化,如今愈来愈多的软件支持64位的指令集。相信终有一天会代替32位汇编成为主流的汇编语言。
    2.arm指令集汇编。
    安卓逆向必备,许多的移动产品cpu都是使用arm指令,如果有兴趣可以深入学习
    3.还有很多指令集,有兴趣可以自由的学习

    其实到了这一步,其实已经可以算作是逆向工程入门了,接下来就是继续向更高的方向前进。
    下面的是逆向工程几个方向分支。感兴趣就去学吧

    1.window逆向工程

    想继续在windows平台下玩耍的话可以选择这个分支。学习软件破解与加密技巧,游戏外挂以及反外挂的技术。病毒的编写以及分析的技术。其实都是建立在逆向工程技术之上的。
    要学windows逆向,首先要对windows的api或者说是系统函数要有详细的了解。推荐两本书:
    1.《windows环境下的32位汇编程序设计》(又名《琢石成器》)以汇编语言讲解WindowsApi,必看。
    2.**《windows程序设计》**window开发界的圣经,不变的经典。

    如果对windows的api有了一定了解之后。可以开始学习windows上逆向工程的更高级技巧了。继续安利两本书:
    1.《加密与解密》看雪出品,必属精品。不可多得的逆向精品书
    2.《逆向工程核心原理》评价挺不错的书,值得一看
    除了看书之外,就是可以找一些ctf或者creakme来练练手了。学到的知识只有通过实践才能够完全掌握。

    2.漏洞利用与防御

    0day攻击。网络安全领域最可怕,最难以防御,后果最严重的攻击方式。掌握着未被公开的0day漏洞的黑客无疑是黑客中最为顶尖的存在。如果你学习linux,希望成为被人崇拜的2进制大牛,就向着这个方向前进吧。

    这个方向资料实在不多,只有一本:《0day安全》依然是看雪出品。因为已经绝版,所以将就看盗版的吧。

    3.安卓逆向

    随着智能手机的普及,逆向工程也开始进入安卓手机平台。如果希望从事安卓逆向的人,可以学习此方向。
    至于学习方法嘛。。。。首先,你要学会安卓开发。其次,你要学会arm指令集。然后开始安卓逆向之路。有一本推荐大家《Android软件安全与逆向分析》还是看雪出品。

    相信对于初学者来说,这么多的方向已经看的够让人眼花缭乱的了。不要惊慌,从最初的c语言开始吧。坚持着一步一步向前。你会慢慢发现逆向工程的世界比我写的更加精彩。

    本人能力所及范围内就只有这一些了。如果有疏忽以及不正确的地方,欢迎指正

    展开全文
  • 人工智能,零基础入门!... 一、新建一个maven项目,pom文件引入jar包依赖: ...-- MBG==MyBatis逆向工程代码生成依赖包 --> <dependency> <groupId>org.mybatis.generator</groupId> <...

    人工智能,零基础入门!http://www.captainbed.net/inner

    一、新建一个maven项目,pom文件引入jar包依赖:

    <!-- MBG==MyBatis逆向工程代码生成依赖包 -->
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.3.5</version>
    </dependency>

    二、添加MBG配置文件generatorConfig.xml

    【1】图解

    generatorConfig.xml配置文件


    【2】详细代码

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
      PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
      "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>
    	<!-- context元素用于指定生成一组对象的环境。targetRuntime:此属性用于指定生成的代码的运行时环境。MyBatis3:*这是默认值*-->
    	<context id="testTables" targetRuntime="MyBatis3">
    		<commentGenerator>
    			<!-- 是否去除自动生成的注释 true:是 : false:否 -->
    			<property name="suppressAllComments" value="true" />
    		</commentGenerator>
    		<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
    		<jdbcConnection 
    		    driverClass="com.mysql.jdbc.Driver"
    			connectionURL="${jdbc.url}" 
    			userId="${jdbc.username}"
    			password="${jdbc.password}">
    		</jdbcConnection>
    		<!-- targetProject:生成PO类的位置 -->
    		<javaModelGenerator targetPackage="com.zzw.pojo"
    			targetProject=".\src\main\java">
    			<!-- enableSubPackages:是否让schema作为包的后缀 -->
    			<property name="enableSubPackages" value="false" />
    			<!-- 从数据库返回的值被清理前后的空格 -->
    			<property name="trimStrings" value="true" />
    		</javaModelGenerator>
            <!-- targetProject:mapper映射文件生成的位置 -->
    		<sqlMapGenerator targetPackage="com.zzw.mapper" 
    			targetProject=".\src\main\java">
    			<!-- enableSubPackages:是否让schema作为包的后缀 -->
    			<property name="enableSubPackages" value="false" />
    		</sqlMapGenerator>
    		<!-- targetPackage:mapper接口生成的位置 -->
    		<javaClientGenerator type="XMLMAPPER"
    			targetPackage="com.zzw.mapper" 
    			targetProject=".\src\main\java">
    			<!-- enableSubPackages:是否让schema作为包的后缀 -->
    			<property name="enableSubPackages" value="false" />
    		</javaClientGenerator>
    		<!-- 指定数据库表 -->
    		<table tableName="test" schema="" >
    		</table>
    	</context>
    </generatorConfiguration>
    

    三、运行MyBatis Generator

    新建一个java类,使用junit测试方式或者main方式启动,这里采用main方法运行方式:

    【1】图

    【2】代码:

    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.mybatis.generator.api.MyBatisGenerator;
    import org.mybatis.generator.config.Configuration;
    import org.mybatis.generator.config.xml.ConfigurationParser;
    import org.mybatis.generator.internal.DefaultShellCallback;
    
    /**
     * 直接运行,生成mybatis代码
     * @author: zheng
     */
    public class GeneratorSqlmap {
    
    	public void generator() throws Exception{
    		List<String> warnings = new ArrayList<String>();
    		boolean overwrite = true;		
    		//指定 逆向工程配置文件	
    		File configFile = new File("src/main/resources/mybatis/generatorConfig.xml"); 
    		ConfigurationParser cp = new ConfigurationParser(warnings);		
    		Configuration config = cp.parseConfiguration(configFile);
    		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
    		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);		
    		myBatisGenerator.generate(null);
    	} 	
    	
    	public static void main(String[] args) throws Exception {		
    		try {
    			GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();			
    			generatorSqlmap.generator();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}		
    	}
    
    }

    四、效果

     

     

     

    展开全文
  • 软件逆向工程的前世今生

    万次阅读 2017-03-23 10:58:04
    一提“破解”、“逆向”等词汇,...软件逆向工程(Software Reverse Engineering)又称软件反向工程,是指从可运行的程序系统出发,运用解密、反汇编、系统分析、程序理解等多种计算机技术,对软件的结构、流程、算
  • 逆向工程

    2019-02-19 18:53:00
    Mybatis官方提供了逆向工程,可以针对单表自动生成mybatis代码(mapper.java\mapper.xml\po类) 在开发中,逆向工程是个很常用的工具 使用工具,则需要引入它本身需要的 jar 包:...
  • 逆向工程简介

    2020-07-29 11:45:20
    Reverse engineering is a process that hackers use to figure out a program’s components and functionalities in order to find vulnerabilities in the program. You recover the original software design by...
  • MyBatis逆向工程代码的生成以及使用详解(持续更新)

    万次阅读 多人点赞 2018-06-07 21:23:50
  • 山塞机, 仿制品, 假名牌这些大家都是耳熟能详, 这些都是指针对一样东西进行模仿,达到功能,外观,性能,物理特征跟被模仿的东西基本上一致, 这就是逆向工程. 我在这里要说的是软件的逆向工程, 是根据一个参照软件,...
  • 逆向工程入门学习(FreeBuf)

    万次阅读 多人点赞 2017-01-21 19:19:45
    逆向工程 (一):汇编、逆向工程基础篇 VillanCh2015-11-24共883215人围观 ,发现 43 个不明物体周边系统安全 本文原创作者:VillanCh 本系列文章将讲解逆向工程的各种知识,难度由浅入深。  ...
  • MyBatis框架的学习(七)——MyBatis逆向工程自动生成代码什么是逆向工程MyBatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表...
  • 逆向工程

    千次阅读 2011-11-02 20:19:50
    逆向工程,有的人也叫反求工程,英文是reverse engineering。 逆向工程(reverse engineering)大意是根据已有的东西和结果,通过分析来推导出具体的实现方法。比如你看到别人写的某个exe程序能够做出某种漂亮的动画...
  • 逆向工程

    2009-10-14 10:49:00
    什么叫逆向工程师 从事,已经知道实物而得出实物数据工作的人逆向工程(Reverse Engineering,RE)是从实物样本获取产品数学模型并制造得到新产品的相关技术,已经成为CAD/CAM系统中一个研究和应用热点,并发展成为...
  • 逆向工程

    热门讨论 2016-11-20 14:53:57
    近期,在班里头开了异常逆向工程的分享,然后在网上看了一些资料,发现他更多的是工具类的东西,所以,故留下一篇资料以备忘。 针对如何学好逆向可以有以下几个方面可以参考: 1、具备基本的编程能力,如c...
  • mybatis逆向工程

    2017-12-21 20:13:53
    mybatis逆向工程,包括mysql,oracle。自动生成mapper文件,可以下载学习学习!!!
  • Mybatis 逆向工程的三种方法

    万次阅读 多人点赞 2018-10-20 14:18:38
    目录Mybatis 逆向工程一、通过 Eclipse 插件完成 Mybatis 逆向工程1. 在线安装 Eclipse 插件2. 新建一个 Java Project 项目3. 编写配置文件4. 使用插件运行二、通过 Java 代码完成 Mybatis 逆向工程1. 新建一个 Java...
  • mybatis逆向工程

    2019-04-29 16:58:01
    mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程 可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml、pojo等) 有了sql表的结构后, 我们就可以利用逆向工程直接生成相应的Dao和...
  • 逆向工程案例

    2013-04-11 22:01:06
    逆向工程是信息安全工程师的必备技能 本文将通过分析一个简单的crackme为大家揭开逆向工程的神秘面纱
  • 逆向工程

    千次阅读 2018-11-14 19:06:20
    Mybatis官方提供了逆向工程,可以针对表自动生成mybatis代码(mapper.java\mapper.xml\po类) 设置三个地方 最终生成: Mybatis中什么时候应该声明jdbcType? 当Mybatis不能自动识别你传入对象的类型时。 什么...
  • 逆向工程是一种分析目标系统的过程,旨在于识别系统的各组件以及组件间关系,以便于通过其它形式、或在较高的抽象层次上,重建系统的表征。 逆向工程权威指南专注于软件的逆向工程,是写给初学者的一本经典指南。...

空空如也

1 2 3 4 5 ... 20
收藏数 54,655
精华内容 21,862
关键字:

逆向工程