反編譯obj文件
『壹』 什麼是編譯器
編譯器
編譯器是一種特殊的程序,它可以把以特定編程語言寫成的程序變為機器可以運行的機器碼。我們把一個程序寫好,這時我們利用的環境是文本編輯器。這時我程序把程序稱為源程序。在此以後程序員可以運行相應的編譯器,通過指定需要編譯的文件的名稱就可以把相應的源文件(通過一個復雜的過程)轉化為機器碼了。
[編輯]編譯器工作方法
首先編譯器進行語法分析,也就是要把那些字元串分離出來。然後進行語義分析,就是把各個由語法分析分析出的語法單元的意義搞清楚。最後生成的是目標文件,我們也稱為obj文件。再經過鏈接器的鏈接就可以生成最後的可執行代碼了。有些時候我們需要把多個文件產生的目標文件進行鏈接,產生最後的代碼。我們把一過程稱為交叉鏈接。
一個現代編譯器的主要工作流程如下:
* 源程序(source code)→預處理器(preprocessor)→編譯器(compiler)→匯編程序(assembler)→目標程序(object code)→連接器(鏈接器,Linker)→可執行程序(executables)
工作原理
編譯是從源代碼(通常為高級語言)到能直接被計算機或虛擬機執行的目標代碼(通常為低級語言或機器言)。然而,也存在從低級語言到高級語言的編譯器,這類編譯器中用來從由高級語言生成的低級語言代碼重新生成高級語言代碼的又被叫做反編譯器。也有從一種高級語言生成另一種高級語言的編譯器,或者生成一種需要進一步處理的的中間代碼的編譯器(又叫級聯)。
典型的編譯器輸出是由包含入口點的名字和地址以及外部調用(到不在這個目標文件中的函數調用)的機器代碼所組成的目標文件。一組目標文件,不必是同一編譯器產生,但使用的編譯器必需採用同樣的輸出格式,可以鏈接在一起並生成可以由用戶直接執行的可執行程序。
編譯器種類
編譯器可以生成用來在與編譯器本身所在的計算機和操作系統(平台)相同的環境下運行的目標代碼,這種編譯器又叫做「本地」編譯器。另外,編譯器也可以生成用來在其它平台上運行的目標代碼,這種編譯器又叫做交叉編譯器。交叉編譯器在生成新的硬體平台時非常有用。「源碼到源碼編譯器」是指用一種高級語言作為輸入,輸出也是高級語言的編譯器。例如: 自動並行化編譯器經常採用一種高級語言作為輸入,轉換其中的代碼,並用並行代碼注釋對它進行注釋(如OpenMP)或者用語言構造進行注釋(如FORTRAN的DOALL指令)。
預處理器(preprocessor)
作用是通過代入預定義等程序段將源程序補充完整。
編譯器前端(frontend)
前端主要負責解析(parse)輸入的源程序,由詞法分析器和語法分析器協同工作。詞法分析器負責把源程序中的『單詞』(Token)找出來,語法分析器把這些分散的單詞按預先定義好的語法組裝成有意義的表達式,語句 ,函數等等。 例如「a = b + c;」前端詞法分析器看到的是「a, =, b , +, c;」,語法分析器按定義的語法,先把他們組裝成表達式「b + c」,再組裝成「a = b + c」的語句。 前端還負責語義(semantic checking)的檢查,例如檢測參與運算的變數是否是同一類型的,簡單的錯誤處理。最終的結果常常是一個抽象的語法樹(abstract syntax tree,或 AST),這樣後端可以在此基礎上進一步優化,處理。
編譯器後端(backend)
編譯器後端主要負責分析,優化中間代碼(Intermediate representation)以及生成機器代碼(Code Generation)。
一般說來所有的編譯器分析,優化,變型都可以分成兩大類: 函數內(intraproceral)還是函數之間(interproceral)進行。很明顯,函數間的分析,優化更准確,但需要更長的時間來完成。
編譯器分析(compiler analysis)的對象是前端生成並傳遞過來的中間代碼,現代的優化型編譯器(optimizing compiler)常常用好幾種層次的中間代碼來表示程序,高層的中間代碼(high level IR)接近輸入的源程序的格式,與輸入語言相關(language dependent),包含更多的全局性的信息,和源程序的結構;中層的中間代碼(middle level IR)與輸入語言無關,低層的中間代碼(Low level IR)與機器語言類似。 不同的分析,優化發生在最適合的那一層中間代碼上。
常見的編譯分析有函數調用樹(call tree),控制流程圖(Control flow graph),以及在此基礎上的變數定義-使用,使用-定義鏈(define-use/use-define or u-d/d-u chain),變數別名分析(alias analysis),指針分析(pointer analysis),數據依賴分析(data dependence analysis)等等。
上述的程序分析結果是編譯器優化(compiler optimization)和程序變形(compiler transformation)的前提條件。常見的優化和變新有:函數內嵌(inlining),無用代碼刪除(Dead code elimination),標准化循環結構(loop normalization),循環體展開(loop unrolling),循環體合並,分裂(loop fusion,loop fission),數組填充(array padding),等等。優化和變形的目的是減少代碼的長度,提高內存(memory),緩存(cache)的使用率,減少讀寫磁碟,訪問網路數據的頻率。更高級的優化甚至可以把序列化的代碼(serial code)變成並行運算,多線程的代碼(parallelized,multi-threaded code)。
機器代碼的生成是優化變型後的中間代碼轉換成機器指令的過程。現代編譯器主要採用生成匯編代碼(assembly code)的策略,而不直接生成二進制的目標代碼(binary object code)。即使在代碼生成階段,高級編譯器仍然要做很多分析,優化,變形的工作。例如如何分配寄存器(register allocatioin),如何選擇合適的機器指令(instruction selection),如何合並幾句代碼成一句等等。
『貳』 怎樣知道一個EXE文件是用什麼語言編寫的怎樣寫的
通過看它和什麼庫鏈接可以猜測出用過哪些語言。
比如 java 語言寫的程序一般不會不與 Java 運行時的 DLL 鏈接(名字好像叫jre.dll),Objective-C 和 Swift 語言寫的程序往往是和objc運行時鏈接的。
C語言鏈接的DLL包括Unix/BSD/Linux系統上的 libc、libxnet 等,和 Windows 上的 Kernel.dll 等。C++也是如此,但鏈接的包括有 libstdcxx,和 Windows 上的 mfc*.dll。
至於是怎樣寫的,就要通過反編譯來看了。
『叄』 java強制類型轉換:int i = (int)obj轉換過程是怎樣的
因為有Integer這個包裝類,
如圖是使用javap -c xx.class命令查看的反編譯代碼,Obj 1 = 1;其實是Obj 1 = Integer.valueOf(1);obj轉int其實是obj轉Integer再調用intvalue()方法轉換成int類型
『肆』 用C++編出的exe文件能否被還原成cpp代碼
可以但是相當不現實。與匯編的精簡不同,C語言的編譯鏈接會把相當多冗餘的演算法帶到Obj和Exe里去(一來為了兼容不同硬體環境把各種演算法都考慮到,二來因為其效率確實遠不如匯編)。一個幾十KB的Exe可能反編譯出一本字典那麼多的源程序。如果你不嫌費事可以上網找C語言的decompile軟體試試。
『伍』 Release文件夾下的其他文件
這些文件有:調試符號.pdb, 這個不要給用戶,否則用戶利用這個很容易反編譯你的軟體. vc60.idb/vc70.idb VC使用,對用戶沒有什麼價值
.obj 連接需要的對象文件.
這些文件都不必給用戶,只需要EXE就行
『陸』 混淆的class文件怎麼進行反編譯
一般情況下Java應用的開發者為了保護代碼不被別人抄襲,在生成class文件的時候都java文件進行了混淆,這種class文件用反編譯工具得到的結果很難看懂,並且不能進行編譯。
從研究的角度,淺析如何讀懂這種反編譯過來的文件。
例子一:賦值
反編譯過來的代碼如下:
Node node;
Node node1 = _$3.getChildNodes().item(0);
node1;
node1;
JVM INSTR swap ;
node;
getChildNodes();
0;
item();
getChildNodes();
0;
item();
getNodeValue();
String s;
s;
原始語句:
Node node;
Node node1 = currDocument.getChildNodes().item(0);
node = node1;
String s = node.getChildNodes().item(0).getChildNodes().item(0).getNodeValue();
註解:
JVM INSTR swap ; //賦值語句
練習:
String s1;
String s8 = node.getChildNodes().item(1).getChildNodes().item(0).getNodeValue();
s8;
s8;
JVM INSTR swap ;
s1;
10;
Integer.parseInt();
int i;
i;
例子二:不帶參數創建對象
反編譯過來的代碼如下:
JVM INSTR new #244 ;
JVM INSTR p ;
JVM INSTR swap ;
CrossTable();
CrossTable crosstable;
crosstable;
原始語句:
CrossTable crosstable = new CrossTable();
註解:
練習:
JVM INSTR new #246 ;
JVM INSTR p ;
JVM INSTR swap ;
Database();
Object obj;
obj;
例子三:帶參數創建對象
反編譯過來的代碼如下:
JVM INSTR new #262 ;
JVM INSTR p ;
JVM INSTR swap ;
String.valueOf(s2);
StringBuffer();
s.substring(j, i);
append();
s6;
append();
toString();
s2;
原始語句:
s2 = (new StringBuffer(String.valueOf(s2))).append(s.substring(j, i)).append(s6).toString();
註解:
此語句實際上是:s2 += s.substring(j, i) + s6;
練習:
例子四:for循環
反編譯過來的代碼如下:
int k = 0;
goto _L4
_L8:
...
k++;
_L4:
if(k < as.length) goto _L8; else goto _L7
原始語句:
for(int k=0;k < as.length;k++)
{
...
}
註解:
例子五:while循環
反編譯過來的代碼如下:
String s1 = "";
goto _L1
_L3:
JVM INSTR new #262 ;
JVM INSTR p ;
JVM INSTR swap ;
String.valueOf(s1);
StringBuffer();
_$2(resultset, s, l);
append();
toString();
s1;
_L1:
if(resultset.next()) goto _L3; else goto _L2
原始語句:
String s1 = "";
while(resultset.next())
{
s1 = s1 + resultSetToString(resultset, s, l);
}
『柒』 一個51單片機C程序,裡面有一個bin的文件,這個bin文件應該包含了幾個重要的函數;能用什麼打開!
這個一般是打不開的,打開就等於是盜用人家的代碼。
lib文件
意義:
lib有靜態lib和動態lib之分。
使用:
lib文件通過編譯才可以使用,編譯分靜態與動態之分。
靜態:
靜態lib將導出聲明和實現都放在lib中。編譯後所有代碼都嵌入到宿主程序
動態:
動態lib相當於一個h文件,是對實現部分(.dll文件)的導出部分的聲明。編譯後只是將導出聲明部分編譯到宿主程序中,運行時候需要相應的dll文件支持
詳細說明:
lib文件是不對外公開的,不能查看一個編譯過後的文件
有幾個選擇:
1。如果你查看有同名的dll文件,可以通過vc自帶的depends查看dll介面
2。通過msdn看你使用的該lib包含的函數名,來查找其對應的頭文件,頭文件裡面有整個lib的函數聲明(可能不全)
3。查看vc或者其他工具安裝目錄下的src目錄,查看函數的代碼
lib文件是二進制文件,所以要查看它的內容,只能反匯編。
用編程語言,打開lib文件的辦法有三個:
1、在object/library moles使用全路徑名;
2、把*.lib放在VC的Lib目錄中
3、修改project setting的Link->Input中的Addtional library path,加入你的目錄。
LIB文件是庫文件(與DLL文件相類似),供其它程序調用的,直接打不開。
內容
一個lib文件是obj文件的集合。當然,其中還夾雜著其他一些輔助信息,目的是為了讓編譯器能夠准確找到對應的obj文件。我們可以通過tlib.exe(在tc2.0下的根目錄)來對lib文件進行操作,你可以把自己生成的obj文件通過tlib命令加入到一個lib文件中,也可以把lib文件內的obj文件進行刪除操作,還可以把內部的obj文件給提取出來。明白了lib文件的大致結構以及對它的具體操作,在學習C語言的過程中,就會又多了一個切入點對C語言具體實現進行研究。
使用步驟
在command下,把當前目錄設置為tlib.exe所在目錄,然後輸入tlib命令回車,此時顯示的內容就是對tlib命令的詳細解釋,語法如下:
Syntax: TLIB libname [/C] [/E] commands, listfile
libname library file pathname
commands sequence of operations to be performed (optional)
listfile file name for listing file (optional)
A command is of the form: <symbol>molename, where <symbol> is:
+ add molename to the library
- remove molename from the library
* extract molename without removing it
-+ or +- replace molename in library
-* or *- extract molename and remove it
/C case-sensitive library
/E create extended dictionary
具體解釋:
tlib libname [/C] [/E] commands, listfile
/C:大小寫敏感標志。該選項不常用,此參數為可選項。
/E:建立擴展字典。建立擴展字典可以加速大的庫文件的連接過程,此參數同樣為可選項。
操作命令(可選項):
+ obj文件名 把指定obj文件添加到lib文件中
- obj文件名 把指定obj文件從lib文件中刪除
* obj文件名 導出指定的obj文件(導出後對應的obj文件在lib文件內仍然存在)
-+ obj文件名 替換指定的obj文件(前提是在lib文件中存在與指定obj文件同名的obj)
-* obj文件名 導出指定的obj文件(導出後把對應的obj文件從lib文件內刪除)
lib文件中obj文件列表(可選項)
此參數說明了命令運行後,生成的對應lib文件的列表文件名。它記錄了當前lib文件內obj文件列表
與dll區別編輯
(1)lib是編譯時需要的,dll是運行時需要的。
如果要完成源代碼的編譯,有lib就夠了。
如果也使動態連接的程序運行起來,有dll就夠了。
在開發和調試階段,當然最好都有。
(2)一般的動態庫程序有lib文件和dll文件。lib文件是必須在編譯期就連接到應用程序中的,而dll文件是運行期才會被調用的。如果有dll文件,那麼對應的lib文件一般是一些索引信息,具體的實現在dll文件中。如果只有lib文件,那麼這個lib文件是靜態編譯出來的,索引和實現都在其中。靜態編譯的lib文件有好處:給用戶安裝時就不需要再掛動態庫了。但也有缺點,就是導致應用程序比較大,而且失去了動態庫的靈活性,在版本升級時,同時要發布新的應用程序才行。
(3)在動態庫的情況下,有兩個文件,一個是引入庫(.LIB)文件,一個是DLL文件,引入庫文件包含被DLL導出的函數的名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到所需要使用的DLL文件,庫中的函數和數據並不復制到可執行文件中,因此在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中所要調用的函數的內存地址,這樣當一個或多個應用程序運行時再把程序代碼和被調用的函數代碼鏈接起來,從而節省了內存資源。從上面的說明可以看出,DLL文件必須隨應用程序一起發行,否則應用程序將會產生錯誤。
載入方法編輯
直接加入
在VC中打開File View一頁,選中工程名,單擊滑鼠右鍵,然後選中"Add Files to Project"菜單,在彈出的文件對話框中選中要加入DLL的LIB文件即可。
設置
打開工程的 Project Settings菜單,選中Link,然後在Object/library moles下的文本框中輸入DLL的LIB文件。
程序代碼
加入預編譯指令#pragma comment (lib,"*.lib"),這種方法優點是可以利用條件預編譯指令鏈接不同版本的LIB文件。因為,在Debug方式下,產生的LIB文件是Debug版本,如Regd.lib;在Release方式下,產生的LIB文件是Release版本,如Regr.lib。
當應用程序對DLL的LIB文件載入後,還需要把DLL對應的頭文件(*.h)包含到其中,在這個頭文件中給出了DLL中定義的函數原型,然後聲明。
詳解
節的概念編輯
Lib格式只有四種類型的節(Section),即First Sec,Second Sec,Longname Sec和Obj Sec;其中Second Sec與Longname Sec是可選節,很多Lib文件中都沒有。而開頭的Singature只是一個標識,它相當於COFF目標文件中的魔法數字。它是一個長度為8的字元串,值為「!<arch>\n」。
First Sec 顧名思義,就是第一個節。它包含了庫中所有的符號名以及這些符號所在的目標文件在庫中的位置(絕對偏移)。
Second Sec 就是第二節。它的內容和First Sec是相同的。不同的是,Second Sec是一個有序表,通過它來查找庫中的符號比通過First Sec來查找要快很多。
Longname Sec 是長名稱節。這一節是一個字元串表。它包含了所有長目標文件名。如果後面的Obj Sec中沒有給出相應的目標文件名,我們就要到這一節中來查找。
Obj Sec 就是目標文件節。這些節中存儲著不同的目標文件的原始數據。
在庫文件中,每一節都有兩個部分。一個部分是頭,另一個部分才是該節的數據;數據緊跟在頭的後面。頭描述了該節數據的類型、長度等信息。這些頭的格式都是相同的。其結構用C語言描述如下:
typedef struct {
char Name[16]; // 名稱
char Time[12]; // 時間
char UserID[6]; // 用戶ID
char GroupID[6]; // 組ID
char Mode[8]; // 模式
char Size[10]; // 長度
char EndOfHeader[2];// 結束符
} SectionHeader;
可以看到,頭中的數據全都是字元串。用字元串的好處是可以提高格式的兼容性,因為在不同的機器上,數據的排列方式是不同的。有的機器是以Little-Endian方式工作,還有的是以Big-Endian方式工作,它們互不兼容(這兩種方式的區別!?請看我的《COFF格式》一文,其中的文件頭一節有說明)。用字元串就不會有這種問題(後面我們將會遇到)。但它也有不方便的地方,就是必須把字元串轉換成數值,多了一個步驟。
在這個結構中,最常用的Name、Size以及EndOfHeader三個成員。Name就是節的名稱啦!Size也很好理解,就是該節數據的長度。其內容為「`\n」(注意,這里沒有打錯,是兩個字元「`」和「\n」)。怎麼樣?有點奇怪吧?為什麼要有這個結束符?每一節的頭長度一定,每節中的數據長度也知道。按順序向下讀不行嗎?答案是:不行!因為每一節之間存在間隙!通常是一個位元組或零個位元組。如果是零個位元組倒好,按順序向下讀是OK的。可是如果不為零的話,這樣讀就要錯位了。要知道錯位沒有,只好用一個結束符來定位了。如果在讀頭的時候發現結束符不對,那就要一個位元組一個位元組地向下查找,直到找到結束符,才能算是對齊了。切記!切記!
當然,通過First Sec或Second Sec中給出的偏移來讀數據就不存在這個問題。不會發生錯位,放心讀吧!
First Sec
第一節,通常就是Lib中的每一個小節。它的名稱是「/」。其數據部分的結構如下:
typedef struct {
unsigned long SymbolNum; // 庫中符號的數量
unsigned long SymbolOffset[n]; // 符號所在目標節的偏移
char StrTable[m]; // 符號名稱字元串表
}FirstSec;
第一個成員SymbolNum是符號的數量。注意!它是以Big-Endian方式儲存的(x86平台上的數據是以Little-Endian方式儲存的。這里應該注意轉換。後面給出的convert函數可以在Little-Endian格式與Big-Endian格式之間進行相互轉換)。
第二個成員SymbolOffset是一個數組,它的長度n就是符號的數量,也就是SymbolNum。這個數組儲存了每一個符號所在的目標節的偏移。我們可以方便地通過它來查找符號所在的目標文件。注意!它也是以Big-Endian格式儲存的。
第三個成員StrTable是一個字元串表,它的長度m就是SectionHeader.Size的值減去(SymbolNum+1)*4。其結構很簡單,就是一堆以『\0』結尾的字元串(和COFF文件中的字元串表結構相同)。在有的系統中,它還可能是以「/\n」這兩個字元結尾的字元串的集合。
很簡單的一個結構,不過有兩個成員的長度是不定的。怎麼才能方便地從Lib中讀出這些數據,留給大家自己想吧!下面我只給出一個進行Little-Endian與Big-Endian互轉的函數。
inline void convert(void * p // 要轉換的數據的指針
,size_tsize = 4 // 數據的長度,long為4,short為2
) {
char * buf=(char*)p;
char temp;
for ( size_t i=0;i<size/2;i++ ) {
temp=buf[i];
buf[i]=buf[size-i-1];
buf[size-i-1]=temp;
}
}
Second Sec
第二節
這一節與第一節很相似!它通常也就是Lib文件的第二個節。它的名字也是「/」(注意:文件中第一個叫「/」的節是第一節,第二個就是第二節)。不過它的結構與第一節有些不同,如下:
typedef struct {
unsigned long ObjNum; // Obj Sec的數量
unsigned long ObjOffset[x]; // 每一個Obj Sec的偏移
unsigned long SymbolNum; // 庫中符號的數量
unsigned short SymbolIdx[n]; // 符號在ObjOffset表中的索引
char StrTable[m]; // 符號名稱字元串表
}SecondSec;
第一個成員ObjNum是庫中Obj Sec的數量。
第二個成員ObjOffset是一個偏移表,它記錄了庫中所有Obj Sec的偏移。這個表的記錄數x就是ObjNum。
第三個成員SymbolNum與First Sec中的SymbolNum意義相同。
第四個成員SymbolIdx變成了一個索引,它記錄了相應名稱字元串在ObjOffset這個表中的位置,我們要通過兩次索引才能找到我們所要符號的Obj Sec位置。它的項目數n為SymbolNum。但請注意,這個索引是unsigned short型,不再是unsigned long型。
第五個成員StrTable結構與First Sec中的一樣。不過,它的長度m為SectionHeader.Size的值減去((ObjNum+1)*4+(SymbolNum+2)*2)。
值得注意的是,這里的所有數據都是Little-Endian格式的。千萬不要弄錯了!Longname Sec
這個小節就是一個字元串表,它的名稱為「//」,其結構同FirstSec.StrTable。這里就不多說了。
Obj Sec
這一節中的數據就是COFF文件的原始數據,把它讀出來存成文件,就是一個COFF文件。它的格式請參考《COFF格式》一文。
要指出的是它的命名方式有些特殊。如果Obj文件的名稱少於16個字元,它就會被保存在SectionHeader的Name成員中,以『/』字元結尾。如果無法保存在Name成員中,則Name成員的第一個字元就為『/』,之後再跟上這個名稱在Longname Sec中的偏移。
例如:
!<arch>\n
……
LongName Sec:
This_Is_Long_Name0001\0
This_Is_Long_Name0002\0
……
Obj Sec1:
Name[16]:「shortname/」
……
Obj Sec2:
Name[16]:「/0」 // 這里使用了第一個長文件名This_Is_Long_Name0001
……
Obj Sec3:
Name[16]:「/22」 // 這里使用了第二個長文件名This_Is_Long_Name0002
『捌』 程序脫殼是什麼意思
殼的概念:
所謂「殼」就是專門壓縮的工具。
這里的壓縮並不是我們平時使用的RAR、ZIP這些工具的壓縮,殼的壓縮指的是針對exe、com、和dll等程序文件進行壓縮,在程序中加入一段如同保護層的代碼,使原程序文件代碼失去本來面目,從而保護程序不被非法修改和反編譯,這段如同保護層的代碼,與自然界動植物的殼在功能上有很多相似的地方,所以我們就形象地稱之為程序的殼。
殼的作用:
1.保護程序不被非法修改和反編譯。
2.對程序專門進行壓縮,以減小文件大小,方便傳播和儲存。
殼和壓縮軟體的壓縮的區別是
壓縮軟體只能夠壓縮程序
而經過殼壓縮後的exe、com和dll等程序文件可以跟正常的程序一樣運行
下面來介紹一個檢測殼的軟體
PEID v0.92
這個軟體可以檢測出 450種殼
新版中增加病毒掃描功能,是目前各類查殼工具中,性能最強的。
另外還可識別出EXE文件是用什麼語言編寫的VC++、Delphi、VB或Delphi等。
支持文件夾批量掃描
我們用PEID對easymail.exe進行掃描
找到殼的類型了
UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo
說明是UPX的殼
下面進行
步驟2 脫殼
對一個加了殼的程序,去除其中無關的干擾信息和保護限制,把他的殼脫去,解除偽裝,還原軟體本來的面目。這個過程就叫做脫殼。
脫殼成功的標志
脫殼後的文件正常運行,功能沒有損耗。
還有一般脫殼後的文件長度都會大於原文件的長度。
即使同一個文件,採用不同的脫殼軟體進行脫殼,由於脫殼軟體的機理不通,脫出來的文件大小也不盡相同。
關於脫殼有手動脫殼和自動脫殼
自動脫殼就是用專門的脫殼機脫 很簡單 按幾下就 OK了
手動脫殼相對自動脫殼 需要的技術含量微高 這里不多說了
UPX是一種很老而且強大的殼 不過它的脫殼機隨處就能找到
UPX本身程序就可以通過
UPX 文件名 -d
來解壓縮 不過這些需要的 命令符中輸入
優點方便快捷 缺點DOS界面
為了讓大家省去麻煩的操作 就產生了一種叫 UPX SHELL的外殼軟體
UPX SHELL v3.09
UPX 外殼程序!
目的讓UPX的脫殼加殼傻瓜化
註:如果程序沒有加殼 那麼我們就可以省去第二步的脫殼了,直接對軟體進行分析了。
脫完後 我們進行
步驟3
運行程序
嘗試注冊
獲取注冊相關信息
通過嘗試注冊 我們發現一個關鍵的字元串
「序列號輸入錯誤」
步驟4
反匯編
反匯編一般用到的軟體 都是 W32Dasm
W32dasm對於新手 易於上手 操作簡單
W32Dasm有很多版本 這里我推薦使用 W32Dasm 無極版
我們現在反匯編WebEasyMail的程序文件easymail.exe
然後看看能不能找到剛才的字元串
步驟5
通過eXeScope這個軟體來查看未能在w32dasm中正確顯示的字元串信息
eXeScope v6.50
更改字體,更改菜單,更改對話框的排列,重寫可執行文件的資源,包括(EXE,DLL,OCX)等。是方便強大的漢化工具,可以直接修改用 VC++ 及 DELPHI 編制的程序的資源,包括菜單、對話框、字元串表等
新版可以直接查看 加殼文件的資源
我們打開eXeScope
找到如下字串符
122,"序列號輸入錯誤 "
123,"恭喜您成為WebEasyMail正式用戶中的一員! "
124,注冊成功
125,失敗
重點是122
步驟6
再次返回 w32dasm
* Possible Reference to String Resource ID=00122: "?鰺e?"
但是雙擊後
提示說找不到這個字串符
不是沒有 是因為 "?鰺e?"是亂碼 w32dasm對於中文顯示不是太好
畢竟不是國產軟體
先把今天會用到的匯編基本指令跟大家解釋一下
mov a,b ;把b的值賦給a,使a=b
call :調用子程序 ,子程序以ret結為
ret :返回主程序
je或jz :若相等則跳轉
jne或jnz :若不相等則跳轉
push xx:xx 壓棧
pop xx:xx 出棧
棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的存儲區。裡面的變數通常是局部變數、函數參數等。
我們搜索
Possible Reference to String Resource ID=00122
因為對E文支持很好
我們來到了
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00406F17(C) //跳轉來自 406F17
|
* Possible Reference to String Resource ID=00125: "1%"
|
:004070DD 6A7D push 0000007D
:004070DF 8D4C2410 lea ecx, dword ptr [esp+10]
:004070E3 E8F75A1200 call 0052CBDF
* Possible Reference to String Resource ID=00122: "?鰺e?"
|
:004070E8 6A7A push 0000007A
:004070EA 8D4C2408 lea ecx, dword ptr [esp+08]
:004070EE E8EC5A1200 call 0052CBDF
我們來到
:00406F01 8B876C080000 mov eax, dword ptr [edi+0000086C]這里是對
:00406F07 8B4C2408 mov ecx, dword ptr [esp+08]
:00406F0B 50 push eax//這兩個eax和ecx入棧就比較讓我們懷疑了
:00406F0C 51 push ecx//產生注冊碼
:00406F0D E8AE381100 call 0051A7C0//這CALL里對注冊位應該會有設置
:00406F12 83C40C add esp, 0000000C
:00406F15 85C0 test eax, eax// 檢測注冊位
:00406F17 0F85C0010000 jne 004070DD //不存在注冊位 就會跳到4070DD就會出現那個錯誤的字串符了
我們記住406F01這個地址
接著進行下一步
步驟7
這一步我們進行的是調試
用到的軟體是ollydbg
好了我們找到了 注冊碼0012AF04 00FD4A10 ASCII ""
但是這個並不是我們的主要目的
我們還要做出屬於自己的注冊機
相信這個是很多人夢寐以求的事情
步驟8
製作注冊機
注冊機我們需要的是一個KEYMAKE的軟體
因為2.0是演示版而且停止更新了
所以我們用1.73版
做一個內存注冊機 需要下面幾個資料
中斷地址:406F0C
中斷次數:1
第一位元組:51
指令長度:1
好了 一個完美的注冊機 就產生了
還不趕快發給你的朋友 炫耀一下
保證讓他迷糊死 佩服得你要死
其實最後還有幾個步驟
就是撰寫破文
不過大家都是新手 這個步驟 就去了吧
不知不覺說了這么多廢話 希望能對大家有些作用
如果有什麼不懂 不理解的事情 請聯系我 或者到論壇發貼
QQ:9595859
MSN:[email protected]
今天的課程就到這里 大家趕快去動手實踐吧~!
--------------------------------------------------------------------------------
-- 作者:admin
-- 發布時間:2005-10-11 11:13:00
-- 實戰查殼脫殼製作破解注冊機最詳細的教程
大家好,我是kcarhc
今天8月1日了 剛從醫院回來 正好凌晨
這期的課程做晚了 這里給大家道個歉
8月1日 如果我沒記錯
是建軍節
既然是建軍節 也要象徵性的弄些東西來
為了建軍節 這期我選擇打擊黑暗勢力--黑社會
那麼今天的主題就是
-----------
迎接建軍節,鏟除黑社會
-----------
首先介紹軟體
黑社會2.0
[功能簡介]:
1 五大必備功能
遠程屏幕; 完全控制; 文件傳送; Telnet; 遠程關機
2 提供IP反彈定位功能
可以通過靜態IP動態域名,網頁文件的方式反彈通知IP.
3 集成vidc客戶端
內網的朋友想用自動上線功能,可以實現了
4 本軟體集成了常用攻擊工具(如OpenTelnet OpenTftp等)
通過IPC拷貝,而且帶有標準的拷貝進度,全球首次面世;
opentelnet就不介紹了,相信大家都知道;
opentftp為本軟體獨創,可以遠程開啟tftp服務;
5 本軟體集成的極速埠掃描器(掃描速度世界領先)
最開始我用的掃描器是大名鼎鼎的SuperScan3.0,感覺速度很慢;
後來改用SSPort1.0 掃描速度有了明顯的提高.
經過速度對比,本軟體掃描速度比SSPort快 1/3 ,是SuperScan的N倍!!!
我的機器是 賽揚700+256M內存,一般掃描速度為180台/秒;
一些號稱可以達到1000台/秒的掃描器在本機上試驗只有120台/秒.
--------------------
准備工作:
安裝黑社會
--------------------
步驟一 查殼
Peid v0.92
ASPack 2.12 -> Alexey Solodovnikov、
--------------------
步驟二 脫殼
手動脫殼
快速脫掉ASPACK所有版本的方法
的OEP關鍵點在下面
0048D3AF 61 POPAD
0048D3B0 75 08 JNZ SHORT 黑社會.0048D3BA
0048D3B2 B8 01000000 MOV EAX,1
0048D3B7 C2 0C00 RETN 0C//402c4a
0048D3BA 68 00000000 PUSH 0
402ca4就是我們要找的OEP
自動脫殼
AspackDie v1.41
這是一個小小的 PE 文件解壓縮器 (EXE, DLL, ...) 她可以解壓縮
自 Aspack 2000 以後的任何 Aspack 版本. 包括:
- Aspack 2000
- Aspack 2001
- Aspack 2.1
- Aspack 2.11
- Aspack 2.11c/d
- Aspack 2.12
- Aspack 2.12a/b
- 一些未知的版本
-------------------
步驟三 試運行程序 發現突破點
看到關鍵字元串
「注冊碼錯誤!」
-------------------
步驟四 W32DASM 尋找突破點
用w32dasm載入已經脫殼的程序
字元串察看
未發現 字元串 而是發現一堆亂碼
大家於是一定想到了第一節的辦法
用EXESCOPE
-------------------
步驟四 察找 字元串
打開eXeScope 並載入 但是發現 都沒有字元串
這項
為啥呢?大家一定會疑問
一般用eXeScope查不到
我們將開始
-------------------
步驟五 查詢軟體的編譯類型
Peid v0.92
Microsoft Visual Basic 5.0 / 6.0
--------------------
步驟六 採用GetVBRes v0.51 對付VB程序
GetVBRes v0.51 一個非常好的VB漢化工具
對於VB程序 我們用專門漢化用的GetVBRes v0.51來對付它
也許有人不理解 為啥用漢化工具呢
其實eXeScope也屬於漢化工具
GetVBRes載入黑社會
發現沒有亂碼了
看到的全是完整的字元
我們找到了
注冊碼錯誤!
這個字元串
接著為了能搞到程序關鍵點地址
我們把「注冊碼錯誤!」
改成111111
為啥改成111111因為111111111
保存修改
---------------------
步驟六 用W32Dasm載入修改後的文件
發現字元串中有111111
那個就是我們修改的 原來是「注冊碼錯誤!」
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004792EF(C)
|
:00479474 B904000280 mov ecx, 80020004
:00479479 B80A000000 mov eax, 0000000A
:0047947E 894D9C mov dword ptr [ebp-64], ecx
:00479481 894DAC mov dword ptr [ebp-54], ecx
:00479484 894DBC mov dword ptr [ebp-44], ecx
:00479487 8D5584 lea edx, dword ptr [ebp-7C]
:0047948A 8D4DC4 lea ecx, dword ptr [ebp-3C]
:0047948D 894594 mov dword ptr [ebp-6C], eax
:00479490 8945A4 mov dword ptr [ebp-5C], eax
:00479493 8945B4 mov dword ptr [ebp-4C], eax
* Possible StringData Ref from Code Obj ->"1111111" //剛才我們看到的注冊嗎錯誤的哦
|
:00479496 C7458C98194100 mov [ebp-74], 00411998
:0047949D C7458408000000 mov [ebp-7C], 00000008
發現跳轉來自到4792EF
安照習慣 我們來到4792EF後 接著向前看
看到一個跳到這里的那個地址
這里是40928C
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00479278(C)
|
:0047928C 8B55E4 mov edx, dword ptr [ebp-1C]
* Reference T MSVBVM60.__vbaStrMove, Ord:0000h
|
:0047928F 8B3578124000 mov esi, dword ptr [00401278]
:00479295 8D4DE0 lea ecx, dword ptr [ebp-20]
:00479298 895DE4 mov dword ptr [ebp-1C], ebx
:0047929B FFD6 call esi
:0047929D 8B4DE8 mov ecx, dword ptr [ebp-18]
:004792A0 6A01 push 00000001
:004792A2 8D55E0 lea edx, dword ptr [ebp-20]
:004792A5 51 push ecx
:004792A6 52 push edx
:004792A7 E8440F0000 call 0047A1F0
:004792AC 8BD0 mov edx, eax
:004792AE 8D4DDC lea ecx, dword ptr [ebp-24]
:004792B1 FFD6 call esi
:004792B3 50 push eax
:004792B4 53 push ebx
* Reference T MSVBVM60.__vbaInStr, Ord:0000h
|
:004792B5 FF15E8114000 Call dword ptr [004011E8]
:004792BB 8BF0 mov esi, eax
:004792BD 8D45E8 lea eax, dword ptr [ebp-18]
:004792C0 F7DE neg esi
:004792C2 8D4DDC lea ecx, dword ptr [ebp-24]
:004792C5 50 push eax
:004792C6 1BF6 sbb esi, esi
:004792C8 8D55E0 lea edx, dword ptr [ebp-20]
:004792CB 51 push ecx
:004792CC 52 push edx
:004792CD F7DE neg esi
:004792CF 6A03 push 00000003
:004792D1 F7DE neg esi
* Reference T MSVBVM60.__vbaFreeStrList, Ord:0000h
|
:004792D3 FF150C124000 Call dword ptr [0040120C]
:004792D9 8D45D4 lea eax, dword ptr [ebp-2C]
:004792DC 8D4DD8 lea ecx, dword ptr [ebp-28]
:004792DF 50 push eax
:004792E0 51 push ecx
:004792E1 6A02 push 00000002
* Reference T MSVBVM60.__vbaFreeObjList, Ord:0000h
|
:004792E3 FF1548104000 Call dword ptr [00401048]
:004792E9 83C41C add esp, 0000001C
:004792EC 663BF3 cmp si, bx
:004792EF 0F847F010000 je 00479474
我們在
004792AC看到下面這些
EAX=0015A47C, (UNICODE "")
EDX=00000000
懷疑EAX為的
為注冊碼
------------------
步驟七 用不確定正確的注冊 嘗試注冊
用
這個注冊後
我們發現 注冊成功
------------------
步驟八 製做注冊機
Keymake v1.73
中斷地址:4792AC
中斷次數:1
第一位元組:8B
指令長度:2
------------------
步驟九 發布注冊機
找一個網站比如黑基或者你的朋友之間
------------------
步驟十 休息
黑社會終於幹掉了
現在去找你的男朋友或者女朋友
老公或者老婆
找個地方聊聊天 放鬆放鬆
告訴他們 你剛剛把黑社會 擺平了
一定很有趣的
------------------
課程結束
------------------
有事情大家可以去論壇
不過你如果性子急
或者嫌我回復的速度慢
我建議你直接聯系我
只要我在 基本可以馬上給你解答
不在可以留言
我的兩個聯系方式
QQ:9595859
MSN:[email protected]
最後 說一個事
我的女朋友最近生病了
所以才導致這期的課程 這么晚才做出來
希望大家能理解我
我還希望大家能祝福她早日康復
不然的話
你們見到我的日子可能會少了
甚至可能會消失在你們眼前
好了不說了 今天就是到此OVER吧
---------- kcarhc
2004年8月1日 凌晨 沈陽
--------------------------------------------------------------------------------
-- 作者:admin
-- 發布時間:2005-10-11 16:42:00
-- 使用OllyDbg快速脫殼
作者:KU-凌
目標:採用ASPACK、UPX加殼的NOTEPAD.EXE
工具:OllyDbg 1.09英文版、DUMP插件、PEditor
系統:Win98SE
關鍵詞: 脫殼、OllyDbg、OD、DUMP、PUSHAD、POPAD
預備知識
大多數殼都有一個共同的特點。在殼准備開始解壓時都要執行PUSHAD,當殼解壓
完時都要調用POPAD。到底PUSHAD和POPAD是什麼干什麼用的呢?其實PUSHAD是用來將
所有普通寄存器順序進棧的指令,POPAD是所有普通寄存器順序出棧指令。POPAD的出
棧順序和PUSHAD相反。殼為了保護寄存器,便在解壓前將所有寄存器進棧保護起來,
當解壓完成後又將寄存器出棧,恢復其原貌,並將IP設置為原程序的OEP。這樣我們就可以通過這個特點快速脫掉多種軟體的殼。
ASPACK篇
先用ASPACK將NOTEPAD.EXE加殼。用OllyDbg(以下簡稱OD)載入。看見游標停在
殼的入口處。
0040D001 >60PUSHAD ;殼的入口。准備開始解壓,保護寄存器
0040D002E8 03000000CALLNOTEPAD.0040D00A
……
我們不管它,直接向下翻頁找POPAD指令。在40D3AF處找到POPAD
……
0040D3AF61POPAD ;解壓完成,恢復寄存器
0040D3B075 08JNZSHORT NOTEPAD.0040D3BA
0040D3B2B8 01000000MOVEAX, 1
0040D3B7C2 0C00RETN0C
0040D3BA68 CC104000PUSHNOTEPAD.004010CC ;返回到原程序OEP處
0040D3BFC3RETN
……
選定40D3AF這一行,F4運行到此處。在這里說明殼已經完成解壓工作。並且返回到原
程序的入口處。F8單步到4010CC,這里便是原程序的OEP。用DUMP插件直接DUMP出來就可以了(在DUMP時注意將入口點改為10CC,即4010CC-400000=10CC,400000是映象基地址)。文件大小是77059位元組,用PEditor重建PE頭便可以了。未壓縮的文件大小是53248位元組,脫殼後的文件大小是60930位元組。
UPX篇
用UPX將NOTEPAD.EXE加殼,然後用OD載入。停在PUSHAD處,用脫ASPACK同樣的方
法,向下翻頁找POPAD。
……
0040E9FE61POPAD
0040E9FF- E9 C826FFFFJMPNOTEPAD.004010CC
……
下面的JMP就是跳轉到程序的OEP處。F4到40E9FF處,F8單步一下,來到OEP處,DUMP出來。DUMP文件的大小是65536位元組,直接就可以運行。為了完美,用PEditor重建PE頭。那麼脫殼後的文件大小是60293位元組。
後記
用上面說的方法,很多種殼都可以快速的手動脫掉。如果你沒有OD的DUMP插件,
可以到新論壇的下載區找。如果實在沒有,也可以直接停在OEP處用PEDump來DUMP。很久沒有寫東西了。這一篇是寫給初學者練手的。其實殼也是軟體,再怎麼復雜都有可能被脫下來。祝你好運。
另外,轉載時請保持本文的完整。
--------------------------------------------------------------------------------
-- 作者:admin
-- 發布時間:2005-10-11 17:10:00
-- 用Ollydbg手脫EncryptPE V1.2003.5.18加殼的DLL
有兄弟讓看看EncryptPE加殼的DLL,我說新版的就不行了,搞不定的。後來看是EncryptPE V1.2003.5.18舊版加殼的,應該用的是老王老師發布的免費版。呵呵,所以脫了一下,順便記錄過程。
大家可以自己用EncryptPE V1.2003.5.18免費版加個EdrLib.dll看看。
—————————————————————————————————
一、避開IAT加密
設置Ollydbg忽略所有的異常選項。用IsDebug 1.4插件去掉Ollydbg的調試器標志。
添加「同時忽略0EEDFADE、C0000008、009B25C、00953D74」異常。
代碼:--------------------------------------------------------------------------------
00877000 60 pushad//進入OD後停在這
00877001 9C pushfd
00877002 64:FF35 00000000 push dword ptr fs:[0]
00877009 E8 79010000 call EdrLib.00877187
--------------------------------------------------------------------------------
下斷:BP IsDebuggerPresent 斷下後取消斷點
現在我們Ctrl+G:711A0000
為何用這個地址?因為V12003518.EPE是相同的。呵呵,鑽了個舊版的空子。
其實可以再BP GetProcAddress,根據返回地址來判斷。如果返回地址是711XXXXX,說明這是V12003518.EPE的調用,就可以取消斷點Ctrl+F9返回了。具體情況以堆棧的返回地址為准。
現在Ctrl+S 在「整個區段」搜索命令序列:
代碼:--------------------------------------------------------------------------------
mov eax,edi
mov edx,dword ptr ss:[ebp-8]
mov dword ptr ds:[eax],edx
xor eax,eax
--------------------------------------------------------------------------------
找到在711A339F處,我們在711A339F處下個 硬體執行 斷點。
現在我們關閉Ollydbg,重新載入這個dll,直接Shift+F9運行,中斷在711A339F處
代碼:--------------------------------------------------------------------------------
711A339F 8BC7 mov eax,edi
711A33A1 8B55 F8 mov edx,dword ptr ss:[ebp-8]
//改為: mov edx,dword ptr ss:[ebp-4] ★ 正確函數寫入
711A33A4 8910 mov dword ptr ds:[eax],edx
711A33A6 33C0 xor eax,eax
711A33A8 5A pop edx
711A33A9 59 pop ecx
711A33AA 59 pop ecx
711A33AB 64:8910 mov dword ptr fs:[eax],edx
711A33AE EB 0A jmp short V1200351.711A33BA
--------------------------------------------------------------------------------
把711A33A1處修改好之後,取消以前下的711A339F處的斷點。
再Ctrl+S搜索命令序列:
代碼:--------------------------------------------------------------------------------
add ebx,4
mov eax,dword ptr ss:[ebp-4C]
add eax,4
--------------------------------------------------------------------------------
找到在711A43C2處,我們在下面xor eax,eax的711A4401下斷。Shift+F9運行
代碼:--------------------------------------------------------------------------------
711A43C2 83C3 04 add ebx,4
711A43C5 8B45 B4 mov eax,dword ptr ss:[ebp-4C]
711A43C8 83C0 04 add eax,4
711A43CB 8945 B4 mov dword ptr ss:[ebp-4C],eax
711A43CE 8B03 mov eax,dword ptr ds:[ebx]
711A43D0 85C0 test eax,eax
711A43D2 0F87 39FDFFFF ja V1200351.711A4111
711A43D8 A1 74C71B71 mov eax,dword ptr ds:[711BC774]
711A43DD 8038 00 cmp byte ptr ds:[eax],0
711A43E0 75 1F jnz short V1200351.711A4401
711A43E2 8B45 C4 mov eax,dword ptr ss:[ebp-3C]
711A43E5 83C0 14 add eax,14
711A43E8 8945 C4 mov dword ptr ss:[ebp-3C],eax
711A43EB 8B45 C4 mov eax,dword ptr ss:[ebp-3C]
711A43EE 8378 0C 00 cmp dword ptr ds:[eax+C],0
711A43F2 76 0D jbe short V1200351.711A4401
711A43F4 8B45 C4 mov eax,dword ptr ss:[ebp-3C]
711A43F7 8378 10 00 cmp dword ptr ds:[eax+10],0
711A43FB 0F87 38FCFFFF ja V1200351.711A4039//循環處理IAT
711A4401 33C0 xor eax,eax//此處下斷! ★
--------------------------------------------------------------------------------
當我們中斷在711A4401處時IAT已經處理完畢,此時就可以用ImportREC得到正確的輸入表了。
因為EncryptPE後面有自校驗,所以我們返回711A33A1處,點右鍵->撤銷選擇,恢復原來的代碼。
—————————————————————————————————
二、得到重定位表信息、獲得OEP
Ctrl+S 在「整個區段」搜索命令序列: