upx加殼-出題過程的學習筆記


gcc -static xxx.c -o xxx

upx為壓縮殼,將可執行文件進行壓縮,當可執行文件過小時加殼會失敗,所以此處采用了靜態鏈接的方式進行編譯;

附上設計的源碼:

#include<stdio.h>
#include<string.h>
#include<windows.h>

int main(){
 int a,b,c,d;
 int i;
 char answer[27];
 char seq1[]="are you a student at AEU?";
 char seq2[]="enter 1 or 0:";
 char seq3[]="welcome to the competition,do you want any hints?";
 char seq4[]="do you think the examiner is handsome?";
 char seq5[]="you are right!";
 char seq6[]="I modified the spack,You should try to remove the pack manually";
 char seq7[]="Listen!the flag is ";
 char seq00[]=" AEU{eeAmi3_";
 char flag[27]="AEU{eeAmi3_6e74rt_handi43}";
 char seq02[]="This is the first time for us to hold the competition,Looking forward to your performance\nHere's a present for you:";
 char seq03[]="Never give up\nNever lose hope.\nAlways have faith,\nIt allows you to cope.\nTrying times will pass,\nAs they always do.";
 char seq04[]="Just have patience,\nYour dreams will come true. \nSo put on a smile,\nYou'll live through your pain.\nKnow it will pass, \nAnd strength you will gain";
 

	 for(i=0;i<strlen(seq1);i++){
		 printf("%c",seq1[i]);
		 Sleep(90);
	 }
	printf("\n");
	puts("enter 1 or 0:");
	scanf("%d",&a);


	if(a){
		for(i=0;i<strlen(seq3);i++){
			printf("%c",seq3[i]);
			Sleep(90);
		}
		printf("\n");

		puts("enter 1 or 0:");
		scanf("%d",&b);
		if(b){
		 	for(i=0;i<strlen(seq4);i++){
				printf("%c",seq4[i]);
				Sleep(90);
			}
			printf("\n");
			puts("enter 1 or 0:");
			scanf("%d",&c);
			if(c){
				for(i=0;i<strlen(seq5);i++){
				printf("%c",seq5[i]);
				Sleep(90);
				}
				printf("\n");
				
				for(i=0;i<strlen(seq6);i++){
				printf("%c",seq6[i]);
				Sleep(90);
				}
				printf("\n");
				for(i=0;i<strlen(seq7);i++){
				printf("%c",seq7[i]);
				Sleep(200);
				}
				for(i=0;i<strlen(seq00);i++){
				printf("%c",seq00[i]);
				Sleep(500);
				}
				Sleep(6000);
				puts(" (*^_^*)");
				puts("are you really want the flag?");
				
				for(i=0;i<strlen(seq02);i++){
				printf("%c",seq02[i]);
				Sleep(80);
				}
				printf("\n");
				for(i=0;i<strlen(seq03);i++){
				printf("%c",seq03[i]);
				Sleep(80);
				}
				printf("\n");
				for(i=0;i<strlen(seq04);i++){
				printf("%c",seq04[i]);
				Sleep(80);
				}
				printf("\n");
				
				for(i=0;i<strlen(seq7);i++){
				printf("%c",seq7[i]);
				Sleep(200);
				}
				for(i=0;i<strlen(flag);i++){
				printf("%c",flag[i]);
				Sleep(900);
				}
				printf("\n");
				
				puts("now,input your answer:");
				scanf("%s",answer);
				
				for(i=0;i<strlen(flag);i++){
					if(flag[i]=='e') flag[i]+=1;
					else if(flag[i]=='r') flag[i]-=1;
				}
				if(!strcmp(answer,flag))
					puts("right!");
				else puts("wrong,Is it really that simple?");
			
				Sleep(6000);

				
			}
			else{
				puts("You can't solve the problem");
			}
		}
		else{
			puts("I can't give you a hint");
			
		}
	}
	else{
		puts("sorry,identity failed");
	}
 return 0;
}

  

upx xxx.exe -o xxx.exe

使用upx工具完成加殼,正常情況下upx工具可以順利完成脫殼

upx -d xxx.exe

但對殼進行修改后該工具便失效。

一,首先認識upx:

upx的作用是壓縮程序代碼,比如可執行文件中的123456用a代替,還會在程序的開頭插入一段代碼(用來解壓縮);當執行該文件時插入的代碼會起作用,將文件解壓,但解壓只能在內存中完成,采用靜態的方式是沒辦法看到解壓后的可執行代碼的。所以通用方法是動態調試,一直追蹤到解壓后的可執行代碼,完成轉儲后也就是脫殼成功。

二、修改upx

本題設計采用修改upx的標志:

 

修改為00 00 00 00

保存后新的文件在upx -d命令下回出錯,此處不演示。設計意圖在於讓解題人手動脫殼,修改方式比較簡單,輔助工具應該也能完成,沒有做過實驗,不在贅述。

upx放脫殼的幾種方法總結:

1.修改區段名,查看一下加殼后的各個段:

 

 

修改掉區段的名字,另存后不影響執行,upx-d失敗;另外的區段名同理。

2.修改特征碼:

pe工具能夠識別出文件被加upx是因為加殼后upx自身的特征碼被識別,我們可以修改特征碼達到使工具識別步出upx的目的;

特征碼:60 BE ?? ?? ?? 00 8D BE ?? ?? ?? FF

 (留坑)

 

3.添加區段:

順便學習了關於PE的相關知識,匯總如下:

 

 可執行文件的代碼和數據分類存儲在各個塊之中,PE頭與區段之間是塊表(說明了各個塊的相關信息)

VA:虛擬地址,即PE文件映射到內存后的地址(虛擬空間 )

RVA:相對虛擬地址,相對於PE載入地址的偏移。 VA=基址+相對虛擬地址

物理地址/文件偏移地址:RAW Offset,某個數據相對於文件頭的偏移,,顯示的地址就是物理地址

 

 主要分析塊表:塊表由IMAGE_SECTION_HEADERS結構體來定義,原形如下:

 

比較晦澀,結合實例分析:

 

 

第一個塊表標黑部分,40個字節,

55 50 58 30 00 00 00 00(8個字節):UPX0字符的十六進制,表示塊名

00 70 00 00(4個字節):VirtualSize,表示實際上的區塊大小(未對齊之前),與區段表中的VSize值剛好對應

00 10 00 00(4個字節):VA,即第一個塊在內存中的映射地址,對應Voffset

00 00 00 00 (4個字節):該塊在磁盤中占用的空間,對應RSize

00 02 00 00 (4個字節):該塊在磁盤中的偏移,對應Roffset

后面連續三段4字節參見結構體定義,最后的80 00 00 E0為塊的屬性標志,定義了是否可讀、可寫、可執行。

重點區分下文件偏移地址和相對虛擬地址,兩者都是相對於頭的偏移;文件偏移地址是塊在磁盤中相對於PE頭的偏移,RVA則是PE加載映射到內存之后相對於頭的偏移。

如圖

 ,如圖分析UPX1的RAWoffset為200,即在PE中地址200開始的地方,往后找大小E00,即為UPX1這個段的實際代碼。

使用lordPE工具添加一個區段,可以使工具不能識別出upx殼。(留坑待補)

 

三、解題:

 脫殼部分采用ESP定律,此處不演示

進入IDA分析:

對比源碼,整體上結構非常簡單,反匯編后略微晦澀,只需要能看懂棧的布局就能明白變量之間的關系;

 

 

 

 

邏輯就是比較str1與str2的值,v30[-95]實際上也是str2,原因如下:

v30為int型,占據4個字節,v30[-95]也就是從v30的地址往前推95*4=380(17Ch)個字節,在棧的布局上來看,v30在棧中的地址是esp+33C,往棧減小的位置推算,33c-17c=1c0,即v30[-95]實際上esp+1c0,對比棧的空間分布,也就是Str2.

其余的變量推算同理。必須要明確的是變量a為int型(占4字節),那么a[i]表示含義是基址加上i個int型的偏移,即4*i個字節。

(32位/64位環境下)

char型數據則占據1字節;double 8字節 ;short 占2字節

#以上參考:

1.從做題到出題再到做題三部曲-UPX - 先知社區 (aliyun.com)

2.《加密解密》

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM