ITPUB论坛-中国最专业的IT技术社区

 找回密码
 注册
查看: 114380|回复: 324

oracle 10-11g下的UNWRAP

[复制链接]
论坛徽章:
1
优秀写手
日期:2014-01-15 06:00:14
发表于 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
发表于 2009-5-1 20:18 | 显示全部楼层
OK,希望楼主继续,我也想了解下这些方面的内容!

使用道具 举报

回复
论坛徽章:
1
优秀写手
日期:2014-01-15 06:00:14
 楼主| 发表于 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:282012新春纪念徽章
日期:2012-01-04 11:50:44茶鸡蛋
日期: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
发表于 2009-5-7 13:08 | 显示全部楼层
好,有开拓精神。

使用道具 举报

回复
论坛徽章:
0
发表于 2009-5-13 10:00 | 显示全部楼层
正在找资料

使用道具 举报

回复
论坛徽章:
395
阿斯顿马丁
日期:2014-01-03 13:53:52马上有对象
日期:2014-04-09 16:19:542014年世界杯参赛球队: 洪都拉斯
日期:2014-06-25 08:25:55itpub13周年纪念徽章
日期:2014-09-28 10:55:55itpub13周年纪念徽章
日期:2014-10-01 15:27:22itpub13周年纪念徽章
日期:2014-10-09 12:04:18马上有钱
日期:2014-10-14 21:37:37马上有钱
日期:2015-01-22 00:39:13喜羊羊
日期:2015-02-20 22:26:07懒羊羊
日期:2015-02-21 22:03:31
发表于 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
发表于 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:20ITPUB十周年纪念徽章
日期:2011-11-01 16:19:41鲜花蛋
日期:2011-11-01 08:02:092012新春纪念徽章
日期:2012-01-04 11:49:54现任管理团队成员
日期:2011-05-07 01:45:082011新春纪念徽章
日期:2011-02-18 11:42:472011新春纪念徽章
日期:2011-01-25 15:42:56
发表于 2009-5-13 12:35 | 显示全部楼层
回复,浏览

使用道具 举报

回复
招聘 : 系统架构师
认证徽章
论坛徽章:
369
秀才
日期:2015-07-14 09:44:30秀才
日期:2015-08-26 09:00:13金牛座
日期:2015-08-28 09:13:22秀才
日期:2015-09-06 10:19:32秀才
日期:2015-09-06 10:42:32巨蟹座
日期:2015-09-09 14:25:25巨蟹座
日期:2015-09-10 09:03:46秀才
日期:2015-09-11 10:43:06秀才
日期:2015-09-21 09:46:16秀才
日期:2015-08-26 09:00:13
发表于 2009-5-13 12:52 | 显示全部楼层
hm...

使用道具 举报

回复
论坛徽章:
1
优秀写手
日期:2014-01-15 06:00:14
 楼主| 发表于 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的应用程序来方便大家使用.

使用道具 举报

回复

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

本版积分规则

SACC2017购票8.8折优惠进行时

2017中国系统架构师大会(SACC2017)将于10月19-21日在北京新云南皇冠假日酒店震撼来袭。今年,大会以“云智未来”为主题,云集国内外顶级专家,围绕云计算、人工智能、大数据、移动互联网、产业应用等热点领域展开技术探讨与交流。本届大会共设置2大主会场,18个技术专场;邀请来自互联网、金融、制造业、电商等多个领域,100余位技术专家及行业领袖来分享他们的经验;并将吸引4000+人次的系统运维、架构师及IT决策人士参会,为他们提供最具价值的交流平台。
----------------------------------------
优惠时间:2017年8月30日前

活动链接>>
TOP技术积分榜 社区积分榜 徽章 电子杂志 团队 统计 虎吧 老博客 知识索引树 读书频道 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档 | IT博客
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛 | SAP ERP系统
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 网站律师 隐私政策 知识产权声明
京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表