oracle wrap加密包破解問題

regonly1發表於2009-11-17

之前從itpub上找到了關於Oracle10g下wrap包的破解方法:
http://www.itpub.net/thread-1154232-1-2.html
總得來說,Oracle加密的原理就是先對原始碼進行lz壓縮lzstr,然後對壓縮資料進行SHA-1運算得到40位的加密串shstr,然後將加密串與壓縮串拼接得到shstr+lzstr,然後對拼接後的字串進行Oracle雙字元轉換(轉換表)。最後將轉換後的字串進行base64編碼,最終得到wrap的加密串。
        上面提供的lz壓縮是一個外接的java包來執行的amosunwrapper.deflate/inflate。但是在呼叫該包的過程中,如果字串過長,則會出現報錯的問題(並不直接由於java包引起)。一直想用Oracle本身提供的方法來實現lz解壓縮。然後就發現了utl_compress這個工具,它提供了lz_compress和lz_uncompress兩個方法。但是透過實際破解發現,利用這兩個函式無法得到解壓縮後的原始碼,都是丟擲ora-29294壓縮格式錯誤的問題。開始以為是中間raw轉換過程或雙字元轉換過程出現了錯誤,但是用amosunwrapper解壓縮卻是可以的。最後經過實際比對發現,utl_compress.lz_compress壓縮的資料和amosunwrapper.deflate壓縮的資料格式上差別很大,而實際上我們透過實踐,已經知道amosunwrapper.inflate能夠正確解壓wrap的壓縮資料,因此懷疑utl_compress包進行的實際上不是lz壓縮,而是其他格式。透過網上查詢,的確發現是這個問題:
http://www.itpub.net/viewthread.php?tid=1179268&pid=14603596&page=1&extra=#pid14603596
這裡描述的更加詳細。
        原來utl_compress所採用的壓縮格式實際上不是lz壓縮,而使gzip壓縮。不知道是不是Oracle為了防止自己的原始碼被輕易破解還是其他原因,用了gzip壓縮演算法替換lz演算法來迷惑我們,讓我們以為wrap的加密串根本不是lz壓縮的。

以下是amosunwrapper和utl_comress兩種壓縮方式的比對:

with tmp1 as (select 'create function a' m from dual),
     tmp2 as (select utl_compress.lz_compress(utl_raw.cast_to_raw(m)) lzstr from tmp1),
     tmp3 as (select lzstr, dbms_crypto.Hash(lzstr, 3)||lzstr shlzstr from tmp2),
     tmp4 as (select lzstr, shlzstr, double_replace(shlzstr) repshlzstr from tmp3),
     tmp5 as (select dbms_ddl.wrap(m) wp from tmp1),
     tmp6 as (select utl_compress.lz_uncompress(lzstr) lz_uncompress,
                     amosunwrapper.inflate(lzstr) uw_uncompress,
                     amosunwrapper.deflate(m, 9) uw_compress
                from tmp2, tmp1)
select --utl_raw.cast_to_varchar2(utl_encode.base64_encode(repshlzstr)) base64decode,
       --substr(wp, instr(wp, chr(10), 1, 20) + 1) subwp,
       --utl_raw.cast_to_varchar2(lz_uncompress) lz_uncompress,
       --uw_uncompress,
       uw_compress,
       lzstr
  from tmp4, tmp5, tmp6;

以下是一個最簡單的破解過程:

declare
    v_str varchar2(1000) := 'create or replace function a(x int, y out varchar2)' ;
    v_str_wrapped  varchar2(1000) := dbms_ddl.wrap(v_str);
    v_str1 varchar2(1000) := substr(v_str_wrapped, instr(v_str_wrapped, chr(10), 1, 20) + 1);
    v_str2 varchar2(1000) := replace(v_str1, chr(10));
    v_b64  raw(1000);
    v_cct  raw(1000);
    v_cps  raw(1000);
begin

    v_b64 := substr(utl_encode.base64_decode(utl_raw.cast_to_raw(v_str2)), 41);
 
    v_cct := double_replace(v_b64, 2);
    lyon.p(utl_raw.cast_to_raw(v_str2), 1);
    lyon.p(v_b64, 1);
    lyon.p(v_cct, 1);
    lyon.p(amosunwrapper.inflate(v_cct), 1);
    --lyon.p(utl_compress.lz_uncompress(v_b64), 1);

    --p(utl_compress.lz_uncompress(v_cct), 1);
    --p(utl_compress.lz_compress(utl_raw.cast_to_raw('function a')), 1);
end;

涉及到的函式和表:
create or replace function double_replace(str varchar2, xway int := 1)
return raw as
    type typ_dic is table of varchar2(2) index by varchar2(2);
    v_dic  typ_dic;
    v_ret  raw(1000);
begin
    if (xway = 1) then
        for c in (select il.* from sys.idltranslate il) loop
            v_dic(c.c_lzdeflatecode) := c.c_base64decode;
        end loop;
    elsif (xway = 2) then
        for c in (select il.* from sys.idltranslate il) loop
            v_dic(c.c_base64decode) := c.c_lzdeflatecode;
        end loop;   
    end if;
    for i in 0 .. length(str)/2 - 1 loop
        v_ret := v_ret || v_dic(substr(str, i*2 + 1, 2));
        --lyon.p('src: ' || substr(str, i*2 + 1, 2) || ' -> dst: ' || v_dic(substr(str, i*2 + 1, 2)), 1);
    end loop;
    return v_ret;
end double_replace;

--idtranslate表
create table IDLTRANSLATE
(
  C_BASE64DECODE  VARCHAR2(2) not null,
  C_LZDEFLATECODE VARCHAR2(2)
);

amosunwrapper就不提供了,想找的很容易找到。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12932950/viewspace-619808/,如需轉載,請註明出處,否則將追究法律責任。

相關文章