查看: 171386|回复: 326

oracle 10-11g下的UNWRAP

[复制链接]
论坛徽章:
1
优秀写手
日期:2014-01-15 06:00:14
跳转到指定楼层
1#
发表于 2009-4-20 16:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  这个问题说了很长时间了。前一段时间对这个比较感兴趣,浏览了不少的外国网站,嘿嘿,吸取他们的先进经验,
         改造改造程序就弄出来了。这里把过程贴出来,跟大家分享,欢迎指正!由于涉及到分析与实践,篇幅稍微长了一点儿,
         成两个部份。
 
   在ORACLE9I下的UNWRAP,老外研究得比较彻底了,由于涉及到语法构成分析,比较麻烦,这里就不多说了,
     只讲讲在10到11G下怎样搞。在这个版本的ORACLE下,UNWRAP的理论依据都来源于
                     "The oracle hacker's handbook" by David Litchfield
         在书中介绍了WRAP后的代码是BASE64编码的,也就是说如果我们要UNWRAP,首先就要进行BASE64
     的解码;其次,书中也告诉我们,解码后的每个字节需要根据一个替换表进行单独的替换;替换后的字符串需要按LZ算法
     进行解压;最终可以得到源码的明文。是不是挺简单的?如果书上说的是正确的,进行UNWRAP唯一的问题就是这个替换表
     了。要得这个替换表,那么我们可以做这样一个假设:
   既然我们通过SQL可以这样对某过程做DBMS_DDL.WRAP加密可以得到密文,如下所示:
   select dbms_ddl.wrap('create procedure a') from dual;
   那么对这部份密文的正文部份进行BASE64解码的值 与 未加密正文('procedure a')直接进行LZ压缩后的值 
   必然是一一对应的,且两个串的长度也是相等的。这是一个重大的前提!通过这种假设,肯定就能得到替换表,替换表是按字
   节来计算的,所以应该有二个列,其中一列代表BASE64解码后的字节值(十六进制00到FF),另一列代表替换列
   (另外提醒一个问题,BASE64列不能出现重复值,哈哈,可以想像得到,如果有重复值就完了)。我的意思就是对密文
   进行BASE64解码后,将对应的密文的正文部份按字节替换成替换表中预先算出来的字节,最后直接按LZ算法进行解压,
   替换表正确的情况下,明文就应该出来了。

  这里需要解释4个问题,密文的正文部份是什么?未加密正文为什么要用'procedure a'而不加上'Create'部份?LZ算法压缩
在ORACLE中怎么办?BASE64编码与解码在ORACLE中怎么办?

  BASE64编码地球人都知道,在ORACLE中有现存的工具包进行编码和解码,我们将用到BASE64的解码,具体
包是:sys.utl_encode.base64_decode。用的时候还需要另一个过程来将字符串转换为RAW格式:sys.utl_raw.cast_to_raw
  LZ压缩很常见,不过懂得内部算法的人很少,ORACLE中也有现存的工具包,我这里用的是老外的一个JAVA包。在
使用这个LZ工具包时,涉及到一个压缩级别参数,这个等级参数不一样,压缩得到的字符串完全一不样。有人可能要问,这样搞
岂不是没法得到替换表了吗?是的,但也不完全正确。因为可供选择的等级参数有限,俺们还能从0等级开始一个一个进行测试,
看到底哪个参数是ORACLE系统用的来WRAP的。嘿嘿,ORACLE用的是“9”等级。
  创建过程或包时如果没有CREATE部份,ORACLE肯定要报错;同样DBMS_DDL.WRAP也不能缺少这个“create”,
否则就要报错。但对于过程或包的SOURCE,查阅系统视图DBA_SOURCE的TEXT列就知道了,肯定没有CREATE这一句。

  说到密文的正文部份,首先要看下面的例子:
  SQL>select dbms_ddl.wrap('create procedure a') from dual;
create procedure a wrapped
a000000
354
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
7
c 38
8BgMHdmA3Qg9IbJmntlZoZQoHwcwg5nnm7+fMr2ywFxakaamb40d1Q=

  这里要解释一下,加密后的代码中354与DB的版本有关,abcd后的7与创建的对象类型有关,也就是7为存储过程,另外的c 38有其他意义,这里就不多说了。从8BgMH开始,BASE64解码后的前二十个字节是SHA1-HASH值(前面那本书说的哈),所以解码后的第二十一个字节开始就是正文了。

  为了下一节的实践活动,嘿嘿,我们先把JAVA包创建好,用以进行LZ压缩与解压,如下所示(全部用SYS用户来做):
create or replace java source named UNWRAPPER
as
import java.io.*;
import java.util.zip.*;

public class UNWRAPPER
{
  public static String Inflate( byte[] src )
  {
    try
    {
      ByteArrayInputStream bis = new ByteArrayInputStream( src );
      InflaterInputStream iis = new InflaterInputStream( bis );
      StringBuffer sb = new StringBuffer();
      for( int c = iis.read(); c != -1; c = iis.read() )
      {
        sb.append( (char) c );
      }
      return sb.toString();
    } catch ( Exception e )
    {
    }
    return null;
  }
  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;
  }
}
/

alter java source UNWRAPPER compile
/

然后用包把JAVA声明进来:

create or replace package amosunwrapper
is
  function deflate( src in varchar2 )
  return raw;
  function deflate( src in varchar2, quality in number )
  return raw;
  function inflate( src in raw )
  return varchar2;
end;
/

create or replace package body amosunwrapper
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 raw )
  return varchar2
  as language java
  name 'UNWRAPPER.Inflate( byte[] ) return java.lang.String';

end;
/


未完待继。。。

[ 本帖最后由 itisamos 于 2011-6-14 17:33 编辑 ]
论坛徽章:
0
2#
发表于 2009-5-1 20:18 | 只看该作者
OK,希望楼主继续,我也想了解下这些方面的内容!

使用道具 举报

回复
论坛徽章:
1
优秀写手
日期:2014-01-15 06:00:14
3#
 楼主| 发表于 2009-5-7 11:54 | 只看该作者
创建好了工具,我们先来看看下面的SQL:


    with src AS ( select 'PACKAGE a' txt  from dual   ),
     wrap as   ( select src.txt , dbms_ddl.wrap( 'create ' || src.txt ) wrap  from src  ),
     subst as  (select substr( utl_encode.base64_decode( utl_raw.cast_to_raw(rtrim( substr( wrap.wrap, instr( wrap.wrap, chr( 10 ), 1, 20 ) + 1 ), chr(10) )  ) ), 41 ) x,
         amosunwrapper.deflate( wrap.txt || chr(0), 9 ) d
       from wrap  )
    select substr( x, r * 2 - 1, 2 )  c_base64,
              substr( d, r * 2 - 1, 2 )  c_translatecode

            from subst  , ( select rownum r from dual connect by rownum <= ( select length( x ) / 2 from subst ) );

结果如下:

C_BASE64 C_TRANSLATECODE
30 78
83 DA
99 0B
B8 70
F5 74
33 F6
9F 76
F5 74
BF 77
5C 55
5A 48
91 64
A6 00
A6 00
CB 0E
C4 B7
E1 02
48 6E


  通过对结果的排序,没有出现同一个BASE64编码对应不同的十六进制的情况,因此我们知道了可以用这个SQL为基础,通过用不同的SOURCE串来产生替换表的内容。

根据上面的SQL俺就可以写首先建一个表来存储替换表的内容,然后写一段PLSQL块来生成替换表的内容:

    SQL>connect sys/XXXX@xxxx as sysdba;

   SQL> CREATE TABLE SYS.IDLTRANSLATE
    (
    C_BASE64DECODE  VARCHAR2(2) NOT NULL,
    C_LZDEFLATECODE VARCHAR2(2)     NULL
    )

/


declare
  nCnt integer;
  nLoop integer;
  nSLoop integer;
  nCharmax integer;
  nCharmin  integer;
  vChar     Varchar2(3);
  cursor getchar is
    with src AS ( select 'PACKAGE '||vChar txt  from dual   ),
     wrap as   ( select src.txt , dbms_ddl.wrap( 'create ' || src.txt ) wrap  from src  ),
     subst as  (select substr( utl_encode.base64_decode( utl_raw.cast_to_raw(rtrim( substr( wrap.wrap, instr( wrap.wrap, chr( 10 ), 1, 20 ) + 1 ), chr(10) )  ) ), 41 ) x,
         amosunwrapper.deflate( wrap.txt || chr(0), 9 ) d
       from wrap  )
    select  substr( x, r * 2 - 1, 2 )  xr ,
    substr( d, r * 2 - 1, 2 )  dr
            from subst  , ( select rownum r from dual connect by rownum <= ( select length( x ) / 2 from subst ) );
begin
    nCharmax:=97;
nCharmin:=122;

For nLoop In 97..122 Loop
  For nSloop In 0..99 Loop
   vChar := chr(nLoop)||to_char(nSloop);
   For abc In getchar Loop
    Select Count(*) Into nCnt From sys.idltranslate WHERE c_base64decode = abc.xr;
    If nCnt < 1 Then
     Insert INTO sys.idltranslate VALUES (abc.xr,abc.dr);
     Commit;
    Else
     Select Count(*) Into ncnt From sys.idltranslate WHERE c_base64decode = abc.xr AND c_lzdeflatecode=abc.dr;
     If nCnt < 1 Then
      DBMS_OUTPUT.PUT_LINE('wrong orginal char:'||vchar||'         hex base64:'||abc.xr);
     End If;
    End If;   
   End Loop;
  End Loop;
End Loop;

end;


   运行上面这段SQL大概会产生1百多条记录,还未达到00-FF总共256条记录的要求,建议替换

select 'PACKAGE '||vChar txt  from dual   中的PACKAGE关健字为procedure或者function类似的,继续运行直到

替换表中有不重复的256条记录为止。

  有了替换表的内容,还有前面的JAVA工具包和ORACLE工具包,已经无限接近终点了!

  俺将在后面写一段程序来验证unwrap的威力,矛头嘛就直接指向ORACLE自身的包了。

使用道具 举报

回复
论坛徽章:
15
2009新春纪念徽章
日期:2009-01-04 14:52:28ITPUB十周年纪念徽章
日期:2011-11-01 16:20:28茶鸡蛋
日期:2011-06-09 12:05:152011新春纪念徽章
日期:2011-02-18 11:43:332010广州亚运会纪念徽章:网球
日期:2010-12-01 20:55:192010广州亚运会纪念徽章:藤球
日期:2010-11-22 15:43:49ITPUB9周年纪念徽章
日期:2010-10-08 09:32:252010年世界杯参赛球队:朝鲜
日期:2010-06-29 15:28:312010新春纪念徽章
日期:2010-03-01 11:06:12生肖徽章2007版:猪
日期:2009-11-13 17:36:11
4#
发表于 2009-5-7 13:08 | 只看该作者
好,有开拓精神。

使用道具 举报

回复
论坛徽章:
0
5#
发表于 2009-5-13 10:00 | 只看该作者
正在找资料

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
6#
发表于 2009-5-13 10:41 | 只看该作者
有趣的研究

将10楼的plsql块改成如下:执行速度更快

set serveroutput on;
Declare
        vWrappedtext                Varchar2(32767);               
        vChar                                        Varchar2(2);
        vRepchar                                Varchar2(2);
        vLZinflatestr                        Varchar2(32767);
        nLen                Integer;
        nLoop        Integer;
        nCnt                Integer;
type vartab is table of varchar2(2) index by varchar2(2);

mytbl vartab;
cursor getchar is select C_BASE64DECODE xr,C_LZDEFLATECODE dr from sys.idltranslate;
Begin
for i in getchar loop --sys.idltranslate表内容存到字符数组
mytbl(i.xr):=i.dr;
end loop;
        select substr( utl_encode.base64_decode( utl_raw.cast_to_raw(rtrim( substr( TEXT, instr( TEXT, chr( 10 ), 1, 20 ) + 1 ), chr(10) )  ) ), 41 ) x                 
                        Into vWrappedtext
                        from DBA_SOURCE
                        Where owner='SYS'
                        And Name = 'DBMS_OUTPUT'
                        And Type='PACKAGE BODY' ;
        --DBMS_OUTPUT.PUT_LINE(vWrappedtext);
    nLen := Length(vWrappedtext)/2 - 1;

        vLZinflatestr :='';
        For nLoop In 0..nLen Loop
                vChar := Substrb(vWrappedtext,nLoop*2+1,2);
                /*
                Select Count(*) Into nCnt From SYS.IDLTRANSLATE Where C_BASE64DECODE=vChar;
                If nCnt <> 1 Then
                        DBMS_OUTPUT.PUT_LINE('SUBSTATION TABLE WARNING: Count not find following char--'||vChar);
                        Return;
                Else
                        Select C_LZDEFLATECODE Into vRepchar From SYS.IDLTRANSLATE Where C_BASE64DECODE=vChar;
                End If;
                */
                vLZinflatestr := vLZinflatestr || mytbl(vChar); --从字符数组匹配
                --DBMS_OUTPUT.PUT_LINE(vLZinflatestr);
        End Loop;
        --DBMS_OUTPUT.PUT_LINE(vLZinflatestr);
        DBMS_OUTPUT.PUT_LINE(amosunwrapper.inflate(vLZinflatestr));
End;


[ 本帖最后由 〇〇 于 2009-6-10 12:49 编辑 ]

使用道具 举报

回复
论坛徽章:
0
7#
发表于 2009-5-13 11:19 | 只看该作者
呵呵,不错,好东西,有意思,继续关注,加油

使用道具 举报

回复
论坛徽章:
67
2015年新春福章
日期:2015-03-06 11:57:312012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-01-04 11:49:54ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41鲜花蛋
日期:2011-11-01 08:02:09现任管理团队成员
日期:2011-05-07 01:45:082011新春纪念徽章
日期:2011-02-18 11:42:472011新春纪念徽章
日期:2011-01-25 15:42:56
8#
发表于 2009-5-13 12:35 | 只看该作者
回复,浏览

使用道具 举报

回复
招聘 : 系统架构师
论坛徽章:
372
双子座
日期:2015-08-18 12:18:21摩羯座
日期:2015-09-20 17:10:27秀才
日期:2015-09-21 09:46:16秀才
日期:2015-09-21 11:16:42秀才
日期:2015-10-08 17:57:58天枰座
日期:2015-10-28 18:28:29秀才
日期:2015-11-11 09:48:44秀才
日期:2015-11-11 10:07:14秀才
日期:2015-11-11 10:22:49秀才
日期:2015-09-11 10:43:06
9#
发表于 2009-5-13 12:52 | 只看该作者
hm...

使用道具 举报

回复
论坛徽章:
1
优秀写手
日期:2014-01-15 06:00:14
10#
 楼主| 发表于 2009-5-20 10:32 | 只看该作者
继续未完的测试哈.废话少说先看代码
set serveroutput on;
Declare
        vWrappedtext                Varchar2(32767);               
        vChar                                        Varchar2(2);
        vRepchar                                Varchar2(2);
        vLZinflatestr                        Varchar2(32767);
        nLen                Integer;
        nLoop        Integer;
        nCnt                Integer;
Begin
        select substr( utl_encode.base64_decode( utl_raw.cast_to_raw(rtrim( substr( TEXT, instr( TEXT, chr( 10 ), 1, 20 ) + 1 ), chr(10) )  ) ), 41 ) x                 
                        Into vWrappedtext
                        from DBA_SOURCE
                        Where owner='SYS'
                        And Name = 'DBMS_MONITOR'
                        And Type='PACKAGE BODY' ;
        --DBMS_OUTPUT.PUT_LINE(vWrappedtext);
    nLen := Length(vWrappedtext)/2 - 1;

        vLZinflatestr :='';
        For nLoop In 0..nLen Loop
                vChar := Substrb(vWrappedtext,nLoop*2+1,2);
                Select Count(*) Into nCnt From SYS.IDLTRANSLATE Where C_BASE64DECODE=vChar;
                If nCnt <> 1 Then
                        DBMS_OUTPUT.PUT_LINE('SUBSTATION TABLE WARNING: Count not find following char--'||vChar);
                        Return;
                Else
                        Select C_LZDEFLATECODE Into vRepchar From SYS.IDLTRANSLATE Where C_BASE64DECODE=vChar;
                End If;
                vLZinflatestr := vLZinflatestr || vRepchar;
                --DBMS_OUTPUT.PUT_LINE(vLZinflatestr);
        End Loop;
        --DBMS_OUTPUT.PUT_LINE(vLZinflatestr);
        DBMS_OUTPUT.PUT_LINE(amosunwrapper.inflate(vLZinflatestr));
End;

   大家可以看看这个程序的输出是什么?  ORACLE的系统包没有秘密可言了,当然其他的用了WRAP的应用存储过程与包也对大家没有秘密了.
  sys.IDLTRANSLATE 的内容,由于牵涉到各方面的因素,我这里就不公开了.相信诸位大大,精通PLSQL,可以通过对代码的分析,得到替换表的内容;本身不太懂SQL的人,得到了这个替换表的内容,我相信也不是什么好事情!
  精通PLSQL的人可以发现这个贴子的破解程序只能针对较小的存储过程或包,这是由于多方面的因素,当然我贪图方便是最大的原因.大大们可以根据这个思路,扩展这个程序,将其改造为适应SOURCE长度超过一行,输出长度也大于4000的应用程序来方便大家使用.

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表