美文网首页我爱编程
Oracle 加密package解密(unwrap)

Oracle 加密package解密(unwrap)

作者: 胡昜 | 来源:发表于2015-09-02 16:54 被阅读2702次

    最近碰到一个问题,需要解密几个使用oracle wrap加密过的程序包,查了下,已经有很多可用的程序,支持10g,11g,连12c都支持。查找过程中,花了点时间研究了下解密的过程,简单记录一下。

    1. 解密算法解析

    要解密,首先要了解加密的原理,在这几个版本的oracle中,解密的理论依据都来源于 "The oracle hacker's handbook" by David Litchfield 这本书,书中介绍了wrap的过程:

    1. 将源码使用lz压缩算法压缩,得到压缩串lzstr
    1. 对压缩串做sha-1运算,得到40位的哈希串shstr
    2. 将哈希串与压缩串拼在一起,shstr+lzstr
    3. 将得到的字符串再按字节执行字典表替换
    4. 再执行base64编码,就得到了加密的字符串

    如果要解密加密以后的字符串,按照以上加密的过程反向推算,可以发现最关键的就是第4步中的字典表替换过程,要解决这个问题,我们就要得到这个替换的字典表,幸运的是,经过测试发现,oracle的这个字典表是固定的按字节映射,所以:
    我们可以通过wrap加密一个简单字符串,比如create PACKAGE a0,得到加密后的密文,然后执行一次base64解码,就能得到替换后的字符串,代码如下

    select substr(utl_encode.base64_decode(utl_raw.cast_to_raw(
               rtrim(substr(wrap_text,
               instr(wrap.wrap,chr(10),1,20) + 1),chr(10)))),
           41) from dual
    

    这里说明一下,wrap以后的密文里,前面20行是没有用的,密文是从第21行开始的,第21行的前40个字符,是拼接的哈希串,从第41个字符开始才是字典表转换后的密文
    本例中,得到的结果为

    78DA0B7074F67674775548346000001185029E
    

    对字符串create PACKAGE a0执行lz压缩,得到字典表转换前的字符串,本例中的结果为

    308399B8F5339FF5BF5C5A2170A6A6F302E141
    

    这样我们得到了转换前和转换后的字符串,就可以按字节建立起我们需要的字典表了,比如本例中:

    转换前-转换后
    30        78
    83        DA
    

    依次类推,我们就可以建立起这个字典表,因为一个字节从00-FF有256个字符,所以相应的这个典表应该有256条记录,这里我们只得到了其中的一部分,还需要选用不同的字符串,多次穷举运算,最终得到全部的记录。事实上,因为这个字典表是固定的,所以得到的结果可以重复使用。当然也可以直接使用别人提供的。
    有了字典表,接下来的工作就比较简单了,按照加密过程反向运算即可:

    1. 从数据库中得到package的密文
    1. base64解码
    2. 字典表反向映射
    3. 去掉前40位哈希串
    4. lz解压缩
    2. 解密程序源码

    这里贴上部分源码,供参考
    LZ解压和压缩的代码,使用java source过程,为了支持比较大的package,使用CLOB作为参数类型,经测试,可以支持较大的程序包

    create or replace java source named CUX_UNWRAPPER
    as
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.Reader;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.zip.Deflater;
    import java.util.zip.InflaterInputStream;
    import oracle.jdbc.OracleDriver;
    import oracle.sql.CLOB;
    
    public class UNWRAPPER {
        //解压缩
        public static CLOB Inflate(CLOB src) throws IOException, SQLException {
            StringBuffer sb = new StringBuffer();
            String s = src.stringValue();
             try{
            ByteArrayInputStream bis = 
                new ByteArrayInputStream(decodeHex(s.toCharArray()));
            //ByteArrayInputStream bis = new ByteArrayInputStream(src);
            InflaterInputStream iis = new InflaterInputStream(bis);
            for (int c = iis.read(); c != -1; c = iis.read()) {
                sb.append((char)c);
            }
            }catch (Exception e)
            {
               e.printStackTrace();
            }
           
            Connection conn = DriverManager.getConnection("jdbc:default:connection:");
            CLOB clob =  CLOB.createTemporary(conn, false, CLOB.DURATION_SESSION);
            clob.setString(1, sb.toString());
            return clob;
    
        }
    
        public static byte[] Deflate(String src, int quality) {
            try {
                byte[] tmp = new byte[src.length() + 100];
                Deflater defl = new Deflater(quality);
                defl.setInput(src.getBytes("UTF-8"));
                defl.finish();
                int cnt = defl.deflate(tmp);
                byte[] res = new byte[cnt];
                for (int i = 0; i < cnt; i++)
                    res = tmp;
                return res;
            } catch (Exception e) {
            }
            return null;
        }
    
        public static int toDigit(char ch, int index) {
            int digit = Character.digit(ch, 16);
            if (digit == -1) {
                throw new RuntimeException("illegal hexadecimal character " + ch + 
                                           " at index " + index);
            }
            return digit;
        }
        
        //16进制字符串转字节数组
        public static byte[] decodeHex(char[] data) {
            int len = data.length;
            if ((len & 0x01) != 0) {
                throw new RuntimeException("odd  number of characters ");
            }
    
            byte[] out = new byte[len >> 1];
    
            for (int i = 0, j = 0; j < len; i++) {
                int f = toDigit(data[j], j) << 4;
                j++;
                f = f | toDigit(data[j], j);
                j++;
                out[i] = (byte)(f & 0xFF);
            }
    
            return out;
        }
    }
    /
    
    --编译java source
    alter java source CUX_UNWRAPPER compile
    /
    

    解密plsql主程序

    --程序包体
    create or replace package body cux_unwrapper is
      function deflate(src in varchar2) return raw is
      begin
        return deflate(src, 6);
      end;
    
      --压缩
      function deflate(src in varchar2, quality in number) return raw as
        language java name 'UNWRAPPER.Deflate( java.lang.String, int ) return byte[]';
    
      --解压缩
      function inflate(src in clob) return clob as
        language java name 'UNWRAPPER.Inflate( oracle.sql.CLOB ) return oracle.sql.CLOB';
      
      --输出clob
      procedure out_put(p_clob clob) is
        l_len     integer;
        l_pos     integer := 1;
        l_chunk   integer := 2000;
        l_buffer  varchar2(4000);
        l_amount  integer;
        l_ins_pos integer := 1;
      begin
        l_len := dbms_lob.getlength(p_clob);
        while l_pos < l_len loop
        
          if l_len - l_pos < l_chunk then
            l_ins_pos := l_len;
          else
            l_ins_pos := dbms_lob.instr(p_clob, chr(10), l_pos + l_chunk, 1);
          end if;
        
          l_amount := l_ins_pos - l_pos + 1;
          dbms_lob.read(p_clob, l_amount, l_pos, l_buffer);
          dbms_output.put_line(l_buffer);
          l_pos := l_ins_pos + 1;
        end loop;
      end out_put;
    
      --解密主程序
      PROCEDURE unwrap(p_owner IN VARCHAR,
                       p_name  IN VARCHAR,
                       p_type  IN VARCHAR) AS
      
        l_wrap varchar2(32767);
      
        l_inf       clob;
        l_res       clob;
        l_src       clob;
        l_inflate   varchar2(32767);
        l_temp      VARCHAR2(32767);
        l_bt        varchar2(32767);
        l_text      varchar2(32767);
        l_char      varchar2(2);
        l_len       number;
        l_slen      integer;
        l_offset    integer := 1;
        l_chunk_len integer := 10080;
      
        --解密字节对照字典表
        l_dict varchar2(512) := '3D6585B318DBE287F152AB634BB5A05F' ||
                                '7D687B9B24C228678ADEA4261E03EB17' ||
                                '6F343E7A3FD2A96A0FE935561FB14D10' ||
                                '78D975F6BC4104816106F9ADD6D5297E' ||
                                '869E79E505BA84CC6E278EB05DA8F39F' ||
                                'D0A271B858DD2C38994C480755E4538C' ||
                                '46B62DA5AF322240DC50C3A1258B9C16' ||
                                '605CCFFD0C981CD4376D3C3A30E86C31' ||
                                '47F533DA43C8E35E1994ECE6A39514E0' ||
                                '9D64FA5915C52FCABB0BDFF297BF0A76' ||
                                'B449445A1DF0009621807F1A82394FC1' ||
                                'A7D70DD1D8FF139370EE5BEFBE09B977' ||
                                '72E7B254B72AC7739066200E51EDF87C' ||
                                '8F2EF412C62B83CDACCB3BC44EC06936' ||
                                '6202AE88FCAA4208A64557D39ABDE123' ||
                                '8D924A1189746B91FBFEC901EA1BF7CE';
        l_sl   varchar2(512) := '000102030405060708090A0B0C0D0E0F' ||
                                '101112131415161718191A1B1C1D1E1F' ||
                                '202122232425262728292A2B2C2D2E2F' ||
                                '303132333435363738393A3B3C3D3E3F' ||
                                '404142434445464748494A4B4C4D4E4F' ||
                                '505152535455565758595A5B5C5D5E5F' ||
                                '606162636465666768696A6B6C6D6E6F' ||
                                '707172737475767778797A7B7C7D7E7F' ||
                                '808182838485868788898A8B8C8D8E8F' ||
                                '909192939495969798999A9B9C9D9E9F' ||
                                'A0A1A2A3A4A5A6A7A8A9AAABACADAEAF' ||
                                'B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF' ||
                                'C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF' ||
                                'D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF' ||
                                'E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF' ||
                                'F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF';
        cursor c_src is
          SELECT src.line, src.text
            FROM DBA_SOURCE src
           WHERE owner = p_owner
             AND Name = p_name
             AND TYPE = p_type
           order by line;
      BEGIN
        dbms_lob.createtemporary(lob_loc => l_inf,
                                 cache   => TRUE,
                                 dur     => dbms_lob.session);
        --取得package密文
        for rec in c_src loop
          l_src := l_src || rtrim(rec.text);
        end loop;
      
         --out_put('source:<'||l_src||'>');
        l_src := rtrim(substr(l_src, instr(l_src, chr(10), 1, 20) + 1), chr(10));
        l_src := replace(l_src, chr(10), '');
        -- dbms_output.put_line('source:<'||l_src||'>');
        --l_src:=substr(l_src,41);
        
        --base64解码
        l_len := dbms_lob.getlength(l_src);
        while l_offset < l_len loop
          if (l_len - l_offset) < 10080 then
            l_chunk_len := (l_len - l_offset);
          end if;
          l_temp := dbms_lob.substr(l_src, l_chunk_len, l_offset);
          l_bt   := utl_encode.base64_decode(utl_raw.cast_to_raw(l_temp));
        
          if l_bt is not null then
            if l_offset = 1 then
              --去掉前40位哈希串
              l_bt := substr(l_bt, 41);
            end if;
            -- l_wrap := l_wrap || l_bt;
            --字典表转换
            l_bt := utl_raw.translate(l_bt, l_sl, l_dict);
          
            l_offset := l_offset + l_chunk_len;
            --    l_inflate := l_inflate || l_bt;
            dbms_lob.writeappend(l_inf, length(l_bt), l_bt);
          end if;
        
        end loop;
      
        /* dbms_output.put_line('base:' || l_wrap);
        dbms_output.put_line('<' || l_inflate || '>');*/
        
        --解压缩
        l_res := inflate(l_inf);
        out_put(l_res);
      END unwrap;
    END;
    /
    

    相关文章

      网友评论

        本文标题:Oracle 加密package解密(unwrap)

        本文链接:https://www.haomeiwen.com/subject/nxelcttx.html