nsa構架_我如何使用NSA的Ghidra解決了一個簡單的CrackMe挑戰

nsa構架

by Denis Nu?iu

丹尼斯·努尤(Denis Nu?iu)

我如何使用NSA的Ghidra解決了一個簡單的CrackMe挑戰 (How I solved a simple CrackMe challenge with the NSA’s Ghidra)

Hello!

你好!

I’ve been playing recently a bit with Ghidra, which is a reverse engineering tool that was recently open sourced by the NSA. The official website describes the tool as:

我最近在玩Ghidra ,這是一種反向工程工具,最近由NSA開源。 官方網站將該工具描述為:

A software reverse engineering (SRE) suite of tools developed by NSA’s Research Directorate in support of the Cybersecurity mission.

由NSA研究部開發的軟件逆向工程(SRE)工具套件,用于支持網絡安全任務。

I’m at the beginning of my reverse engineering career, so I didn’t do anything advanced. I don’t know what features to expect from a professional tool like this, if you’re looking to read about advanced Ghidra features this is likely not the article for you.

我正處于逆向工程職業的開始,所以我沒有做任何高級工作。 我不知道從這樣的專業工具中可以獲得什么功能,如果您想閱讀有關Ghidra的高級功能的信息,那么這篇文章可能不適合您。

In this article I will try to solve a simple CrackMe challenge that I’ve found on the website root-me. The challenge I’m solving is called ELF - CrackPass. If you want to give it try by yourself, then you should consider not reading this article because it will spoil the challenge from you.

在本文中,我將嘗試解決在root-me網站上發現的一個簡單的CrackMe挑戰。 我要解決的挑戰稱為ELF-CrackPass 。 如果您想自己嘗試一下,那么您應該考慮不閱讀本文,因為它會破壞您的挑戰。

Let’s get started! I open up Ghidra and create a new Project which I call RootMe.

讓我們開始吧! 我打開Ghidra并創建一個名為RootMe的新項目。

Then I import the challenge file by dragging it to the project folder. I will go with the defaults.

然后,通過將挑戰文件拖到項目文件夾中來導入它。 我將使用默認值。

After being presented with some info about the binary file, I press OK, select the file, and double click it. This opens up Ghidra’s code browser utility and asks if I want to analyse the file, then I press Yes and go on with the defaults.

在顯示了有關二進制文件的一些信息之后,我按OK,選擇文件,然后雙擊它。 這將打開Ghidra的代碼瀏覽器實用程序,并詢問我是否要分析文件,然后按“是”并繼續使用默認值。

After we import the file, we get some information about the binary file. If we press OK and dismiss this window, and then double click the file we imported, this opens up Ghidra’s code browser utility. I select Yes when prompted to analyze the binary and go on with the defaults.

導入文件后,我們將獲得有關二進制文件的一些信息。 如果我們按OK并關閉此窗口,然后雙擊我們導入的文件,這將打開Ghidra的代碼瀏覽器實用程序。 當提示您分析二進制文件并繼續使用默認值時,我選擇“是”。

The Code Browser is quite convenient. In the left panel we get to see the disassembly view and in the right panel the decompile view.

代碼瀏覽器非常方便。 在左側面板中,我們可以看到反匯編視圖,在右側面板中,可以看到反編譯視圖。

Ghidra shows us directly the ELF header info and the entry point of the binary. After double clicking the entry point, the dissembler view jumps to the entry function.

Ghidra直接向我們顯示了ELF標頭信息和二進制文件的入口點。 雙擊入口點后,反匯編器視圖跳轉到入口功能。

Now we can successfully identify the main function, which I rename to main. It would be nice if the tool would attempt to automatically detect the main function and rename it accordingly.

現在我們可以成功識別main函數,我將其重命名為main。 如果該工具嘗試自動檢測主要功能并相應地對其進行重命名,那就太好了。

Before analyzing the main function, I wanted to change its signature. I changed the return type to int and corrected the parameters’ type and name. This change has taken effect in the decompile view which is cool! ?

在分析主要功能之前,我想更改其簽名。 我將返回類型更改為int并更正了參數的類型和名稱。 此更改已在反編譯視圖中生效,這很酷! ?

Highlighting a line in the decompile view also highlights it in the assembly view.

在反編譯視圖中突出顯示一行,在裝配視圖中也突出顯示該行。

Let’s explore the FUN_080485a5 function, which I’ll rename to CheckPassword.

讓我們探索FUN_080485a5函數,我將其重命名為CheckPassword。

The contents of the CheckPassword function can be found below. I’ve copied the code directly from Ghidra’s decompile view, which is a neat feature that many tools of this type lack! Being able to copy assembly and code is a nice to have feature.

CheckPassword函數的內容可以在下面找到。 我直接從Ghidra的反編譯視圖復制了代碼,這是許多此類工具所缺乏的一項精巧功能! 能夠復制程序集和代碼是很不錯的功能。

void CheckPassword(char *param_1) {   ushort **ppuVar1;   int iVar2;   char *pcVar3;   char cVar4;   char local_108c [128];   char local_100c [4096];   cVar4 = param_1;       if (cVar4 != 0) {          ppuVar1 = __ctype_b_loc();           pcVar3 = param_1;           do {               if (((byte )(ppuVar1 + (int)cVar4) & 8) == 0) {         puts("Bad password !");                     /* WARNING: Subroutine does not return */         abort();       }       cVar4 = pcVar3[1];       pcVar3 = pcVar3 + 1;     } while (cVar4 != 0);   }   FUN_080484f4(local_100c,param_1);   FUN_0804851c(s_THEPASSWORDISEASYTOCRACK_08049960,local_108c);   iVar2 = strcmp(local_108c,local_100c);   if (iVar2 == 0) {     printf("Good work, the password is : \n\n%s\n",local_108c);   }   else {     puts("Is not the good password !");   }   return; }

After taking a look at the code, I’ve come to the following conclusions. The block with the if checks if the user has provided a password and inspects the provided password to check if it’s a valid character or something. I’m not exactly sure what it’s checking for, but here’s what __ctype_b_loc()’s documentation says:

看了一下代碼之后,我得出以下結論。 帶有if的塊檢查用戶是否提供了密碼,并檢查提供的密碼以檢查它是否是有效字符或其他內容。 我不確定要檢查什么,但這是__ctype_b_loc()的文檔所說的內容:

The __ctype_b_loc() function shall return a pointer into an array of characters in the current locale that contains characteristics for each character in the current character set. The array shall contain a total of 384 characters, and can be indexed with any signed or unsigned char (i.e. with an index value between 128 and 255). If the application is multi-threaded, the array shall be local to the current thread.

__ctype_b_loc()函數應將指針返回到當前語言環境中的字符數組,該數組包含當前字符集中每個字符的特征。 該數組總共應包含384個字符,并且可以使用任何有符號或無符號char(即,索引值介于128和255之間)進行索引。 如果應用程序是多線程的,則該數組應位于當前線程的本地。

Anyways, that block of code is not really worth the time, because it doesn’t modify our password in any way, it just verifies it. So we can skip this kind of verification.

無論如何,那段代碼確實不值得花時間,因為它不會以任何方式修改我們的密碼,而只是對其進行驗證。 因此,我們可以跳過這種驗證。

The next function called is FUN_080484f4. Looking at its code, we can tell that it’s just a custom memcopy implementation. Instead of copying the C code from the decompiler view, I copied the assembly code — yes, this is fun.

下一個調用的函數是FUN_080484f4。 查看其代碼,我們可以看出它只是一個自定義的內存復制實現。 我沒有從反編譯器視圖復制C代碼,而是復制了匯編代碼-是的,這很有趣。

*************************************************************                     *                           FUNCTION                                               *************************************************************                     undefined  FUN_080484f4 (undefined4  param_1 , undefined4  p     undefined         AL:1           <RETURN>     undefined4        Stack[0x4]:4   param_1                                 XREF[1]:     080484f8 (R)        undefined4        Stack[0x8]:4   param_2                                 XREF[1]:     080484fb (R)                        FUN_080484f4                                    XREF[1]:     CheckPassword:080485f5 (c)    080484f4 55              PUSH       EBP 080484f5 89  e5           MOV        EBP ,ESP 080484f7 53              PUSH       EBX 080484f8 8b  5d  08       MOV        EBX ,dword ptr [EBP  + param_1 ] 080484fb 8b  4d  0c       MOV        ECX ,dword ptr [EBP  + param_2 ] 080484fe 0f  b6  11       MOVZX      EDX ,byte ptr [ECX ] 08048501 84  d2           TEST       DL,DL 08048503 74  14           JZ         LAB_08048519 08048505 b8  00  00       MOV        EAX ,0x0             00  00                         LAB_0804850a                                    XREF[1]:     08048517 (j)    0804850a 88  14  03       MOV        byte ptr [EBX  + EAX *0x1 ],DL 0804850d 0f  b6  54       MOVZX      EDX ,byte ptr [ECX  + EAX *0x1  + 0x1 ]             01  01 08048512 83  c0  01       ADD        EAX ,0x1 08048515 84  d2           TEST       DL,DL 08048517 75  f1           JNZ        LAB_0804850a                         LAB_08048519                                    XREF[1]:     08048503 (j)    08048519 5b              POP        EBX 0804851a 5d              POP        EBP 0804851b c3              RETComment: param_1 is dest, param_2 is src. 08048501 checks if src is null and if it is it returns else it initializes EAX (index, current_character) with 0. The next instructions move bytes into EBX (dest) from EDX (src).The loop stops when EDX is null.

And the other function FUN_0804851c generates the password from the “THEPASSWORDISEASYTOCRACK” string. Looking at the decompiled view. we can roughly see how this function works. If we didn’t have that, we would need to manually analyze every assembly instruction from the function to understand what it does.

另一個功能FUN_0804851c從“ THEPASSWORDISEASYTOCRACK”字符串生成密碼。 查看反編譯視圖。 我們可以大致了解此功能的工作原理。 如果沒有,我們將需要手動分析函數中的每個匯編指令以了解其功能。

Then, we compare the previously generated password with the password that we got from the user (the first argument, argv[1]). If it matches, the program says good job and prints it, else it prints an error message.

然后,我們將先前生成的密碼與從用戶那里獲得的密碼(第一個參數argv [1])進行比較。 如果匹配,則程序會說好并打印,否則會打印錯誤消息。

From this basic analysis, we can conclude that if we patch the program in various places, we can get it to spit the password without us needing to reverse any C function and write code. Patching the program means changing some of its instructions.

從這個基礎分析中,我們可以得出結論,如果我們在不同的地方打補丁程序,我們就可以吐出密碼,而無需反轉任何C函數和編寫代碼。 修補程序意味著更改其某些指令。

Let’s see what we have to patch:

讓我們看看我們需要修補的內容:

At address 0x0804868c we patch the JNS instruction into a JMP. And voilà, the change is reflected in the decompiler view. The ptrace result check is bypassed.

在地址0x0804868c,我們將JNS指令修補到JMP中。 而且,更改反映在反編譯器視圖中。 ptrace結果檢查被繞過。

{   ptrace(PTRACE_TRACEME,0,1,0);   if (argc != 2) {     puts("You must give a password for use this program !");                     /* WARNING: Subroutine does not return */     abort();   }   CheckPassword(argv[1]);   return 0;}

At address 0x080485b8 we patch the JZ instruction into a JMP. We bypass that password verification block we saw earlier.

在地址0x080485b8,我們將JZ指令修補為JMP。 我們繞過了前面看到的密碼驗證塊。

void CheckPassword(undefined4 param_1) {   int iVar1;   char local_108c [128];   char local_100c [4096];   CustomCopy(local_100c,param_1);      GeneratePassword(s_THEPASSWORDISEASYTOCRACK_08049960,local_108c);   iVar1 = strcmp(local_108c,local_100c);   if (iVar1 == 0) {     printf("Good work, the password is : \n\n%s\n",local_108c);   }   else {     puts("Is not the good password !");   }   return; }

At address 0x0804861e we patch JNZ to JZ. This inverts the if/else condition. Since we don’t know the password, we’re going to submit a random password that is not equal to the generated one, thus executing the printf on the else block.

在地址0x0804861e,我們將JNZ修補到JZ。 這將反轉if / else條件。 由于我們不知道密碼,因此我們將提交一個與生成的密碼不相等的隨機密碼,從而在else塊上執行printf。

void CheckPassword(undefined4 param_1) {   int iVar1;   char local_108c [128];   char local_100c [4096];   CustomCopy(local_100c,param_1);   // constructs the password from the strings and stores it in   // local_108c    GeneratePassword(s_THEPASSWORDISEASYTOCRACK_08049960,local_108c);   iVar1 = strcmp(local_108c,local_100c);   if (iVar1 == 0) { // passwords are equal     puts("Is not the good password !");   }   else {     printf("Good work, the password is : \n\n%s\n",local_108c);   }   return; }

That’s all!

就這樣!

Now we run the program. In other tools we just save the file and it works, but in Ghidra it seems that we need to export it.

現在我們運行程序。 在其他工具中,我們只保存文件即可使用,但是在Ghidra中,似乎我們需要將其導出。

To export the program, we go to File -> Export Program (O). We change the format to binary and click OK.

要導出程序,我們轉到文件->導出程序(O)。 我們將格式更改為二進制,然后單擊“確定”。

I get the exported program on my desktop but it doesn’t work — I couldn’t manage to run the exported program. After trying to read it’s header with the readelf -h program, I get the following output:

我在桌面上獲得了導出的程序,但是它不起作用-我無法設法運行導出的程序。 嘗試使用readelf -h程序讀取其標頭后,得到以下輸出:

root@DESKTOP:/mnt/c/users/denis/Desktop# readelf -h Crack.bin ELF Header:   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF32   Data:                              2's complement, little endian   Version:                           1 (current)   OS/ABI:                            UNIX - System V   ABI Version:                       0   Type:                              EXEC (Executable file)   Machine:                           Intel 80386   Version:                           0x1   Entry point address:               0x8048440   Start of program headers:          52 (bytes into file)   Start of section headers:          2848 (bytes into file)   Flags:                             0x0   Size of this header:               52 (bytes)   Size of program headers:           32 (bytes)   Number of program headers:         7   Size of section headers:           40 (bytes)   Number of section headers:         27   Section header string table index: 26 readelf: Error: Reading 1080 bytes extends past end of file for section headers

Shame. It looks like Ghidra has messed up the file header… and, right now I don’t want to manually fix headers. So I fired up another tool and applied the same patches to the file, saved it, ran it with a random argument and validated the flag.

恥辱。 看來Ghidra弄亂了文件頭 ……而且,現在我不想手動修復頭。 因此,我啟動了另一個工具,并對文件應用了相同的補丁程序,將其保存,并使用隨機參數運行它并驗證了標志。

結論 (Conclusions)

Ghidra is a nice tool with a lot of potential. In its current state, it’s not that great but it works. I’ve also encountered a weird scrolling bug while running it on my laptop.

Ghidra是一個很有潛力的好工具。 在目前的狀態下,它還不是很好,但是可以工作。 在筆記本電腦上運行時,我還遇到了奇怪的滾動錯誤。

The alternatives would be to pay $$ for other tools of this kind, make your own tools, or work with free but not so user friendly tools.

替代方案是為此類其他工具支付$$費用,自己制作工具或使用免費但不那么用戶友好的工具。

Let’s hope that once the code is released, the community will start doing fixes and improve Ghidra.

希望一旦代碼發布,社區將開始進行修復并改進Ghidra。

Thanks for reading!

謝謝閱讀!

翻譯自: https://www.freecodecamp.org/news/how-i-solved-a-simple-crackme-challenge-with-the-nsas-ghidra-d7e793c5acd2/

nsa構架

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/392170.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/392170.shtml
英文地址,請注明出處:http://en.pswp.cn/news/392170.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分布與并行計算—生產者消費者模型隊列(Java)

在生產者-消費者模型中&#xff0c;在原有代碼基礎上&#xff0c;把隊列獨立為1個類實現&#xff0c;通過公布接口&#xff0c;由生產者和消費者調用。 public class Consumer implements Runnable {int n;CountDownLatch countDownLatch;public Consumer(BlockingQueue<In…

python 日志內容提取

問題&#xff1a;如下&#xff0c;一個很大的日志文件&#xff0c;提取 start: 到 end: 標志中間的內容 日志文件a.log xxxxx yyyyy start: start: hahahaha end: start: hahahahha end: ccccccc kkkkkkk cdcdcdcd start: hahahaha end: code import reisfindFalse with open(&…

同一服務器部署多個tomcat時的端口號修改詳情

2019獨角獸企業重金招聘Python工程師標準>>> 同一服務器部署多個tomcat時&#xff0c;存在端口號沖突的問題&#xff0c;所以需要修改tomcat配置文件server.xml&#xff0c;以tomcat7為例。 首先了解下tomcat的幾個主要端口&#xff1a;<Connector port"808…

linux優盤驅動目錄,Linux U盤加載陣列卡驅動步驟(.dd或img).doc

Linux U盤加載陣列卡驅動步驟(.dd或img)如果沒有Linux的機器,可以使用安裝光盤的Linux環境&#xff1a;將?U?盤完全慢速格式化&#xff0c;將驅動拷貝到U盤&#xff0c;將U盤插在服務器上&#xff0c;用Linux安裝光盤第一張啟動到圖形安裝界面&#xff0c;按Ctrl&#xff0b;…

第一章-從雙向鏈表學習設計

鏈表學習鏈表是一種動態的數據結構使用節點作為鏈表的基本單位存儲在節點包括數據元素和節點指針一個完整的數據鏈表應包括轉載于:https://www.cnblogs.com/cjxltd/p/7125747.html

twitter 數據集處理_Twitter數據清理和數據科學預處理

twitter 數據集處理In the past decade, new forms of communication, such as microblogging and text messaging have emerged and become ubiquitous. While there is no limit to the range of information conveyed by tweets and texts, often these short messages are …

ios 動態化視圖_如何在iOS應用中使高度收集視圖動態化

ios 動態化視圖by Payal Gupta通過Payal Gupta 如何在iOS應用中使集合視圖的高度動態化 (How to make height of collection views dynamic in your iOS apps) 充滿活力&#xff0c;就像生活一樣… (Be dynamic, just like life…) Table views and collection views have alw…

新開通博客

新開通博客&#xff0c;希望兄弟們積極更新。 轉載于:https://www.cnblogs.com/ydhliphonedev/archive/2011/07/28/2119720.html

思維導圖分析http之http協議版本

1.結構總覽 在http協議這一章&#xff0c;我將先后介紹上圖六個部分&#xff0c;本文先介紹http的協議版本。 2.http協議版本 http協議的歷史并不長&#xff0c;從1991的0.9版本到現在(2017)僅僅才20多年&#xff0c;算算下來,http還是正處青年&#xff0c;正是大好發展的好時光…

分布與并行計算—生產者消費者模型RabbitMQ(Java)

連接工具 public class ConnectionUtil {public static final String QUEUE_NAME"firstQueue";private static final String RABBIT_HOST "11";private static final String RABBIT_USERNAME "";private static final String RABBIT_PASSWORD…

飛騰 linux 內核,FT2004-Xenomai

移植Xenomai到基于飛騰FT2004 CPU的FT Linux系統1 目前飛騰FT2000/4相關設備驅動還沒有開源&#xff0c;需要先聯系飛騰軟件生態部獲取FT Linux源代碼2 如需在x86交叉編譯arm64內核&#xff0c;推薦使用Linaro gcc編譯器&#xff0c;鏈接如下&#xff1a;https://releases.lina…

使用管道符組合使用命令_如何使用管道的魔力

使用管道符組合使用命令Surely you have heard of pipelines or ETL (Extract Transform Load), or seen some method in a library, or even heard of any tool to create pipelines. However, you aren’t using it yet. So, let me introduce you to the fantastic world of…

關于網頁授權的兩種scope的區別說明

關于網頁授權的兩種scope的區別說明 1、以snsapi_base為scope發起的網頁授權&#xff0c;是用來獲取進入頁面的用戶的openid的&#xff0c;并且是靜默授權并自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁&#xff08;往往是業務頁面&#xff09; 2、以snsapi_userinfo為…

安卓流行布局開源庫_如何使用流行度在開源庫之間進行選擇

安卓流行布局開源庫by Ashish Singal通過Ashish Singal 如何使用流行度在開源庫之間進行選擇 (How to choose between open source libraries using popularity) Through my career as a product manager, I’ve worked closely with engineers to build many technology prod…

TCP/IP分析(一) 協議概述

各協議層分工明確 轉載于:https://www.cnblogs.com/HonkerYblogs/p/11247604.html

window 下分linux分區,如何在windows9x下訪問linux分區

1. 簡 介Linux 內 核 支 持 眾 多 的 文 件 系 統 類 型, 目 前 它 可 以 讀 寫( 至 少 是 讀) 大 部 分 的 文 件 系 統.Linux 經 常 與Microsoft Windows 共 存 于 一 個 系 統 或 者 硬 盤 中.Linux 對windows9x/NT 的 文 件 系 統 支 持 的 很 好, 反 之 你 想 在windows 下…

C# new關鍵字和對象類型轉換(雙括號、is操作符、as操作符)

一、new關鍵字 CLR要求所有的對象都通過new來創建,代碼如下: Object objnew Object(); 以下是new操作符做的事情 1、計算類型及其所有基類型(一直到System.Object,雖然它沒有定義自己的實例字段)中定義的所有實例字段需要的字節數.堆上每個對象都需要一些額外的成員,包括“類型…

JDBC01 利用JDBC連接數據庫【不使用數據庫連接池】

目錄&#xff1a; 1 什么是JDBC 2 JDBC主要接口 3 JDBC編程步驟【學渣版本】 5 JDBC編程步驟【學神版本】 6 JDBC編程步驟【學霸版本】 1 什么是JDBC JDBC是JAVA提供的一套標準連接數據庫的接口&#xff0c;規定了連接數據庫的步驟和功能&#xff1b;不同的數據庫提供商提供了一…

leetcode 778. 水位上升的泳池中游泳(并查集)

在一個 N x N 的坐標方格 grid 中&#xff0c;每一個方格的值 grid[i][j] 表示在位置 (i,j) 的平臺高度。 現在開始下雨了。當時間為 t 時&#xff0c;此時雨水導致水池中任意位置的水位為 t 。你可以從一個平臺游向四周相鄰的任意一個平臺&#xff0c;但是前提是此時水位必須…

2020年十大幣預測_2020年十大商業智能工具

2020年十大幣預測In the rapidly growing world of today, when technology is expanding at a rate like never before, there are plenty of tools and skills to explore, learn, and master. In this digital and data age, Business Information and Intelligence have cl…