这个 ARM 汇编代码有什么作用?

逆向工程 艾达 拆卸 手臂
2021-07-05 13:11:27

我试图找出用于访问 U-Boot shell 的密码,正如我在上一个问题中提到的

我无法理解代码的工作原理。这是来自 IDA 的代码图像。黄色框(loc_8080FF28)中的部分是我不明白的。它对用户输入做了什么?另外我想了解橙色框中的子程序(sub_8081ECE4)对用户输入的作用。我添加了一些我认为相关的评论。在此处输入图片说明

这是文本形式的代码:

loc_8080FF10
ADD R4, R4, #1
LDR R0, =aDstInputPasswd ; "\n%dst input Passwd:"
MOV R5, #0
MOV R1, R4      ; R4 = num of tries so far
BL  printf
B   loc_8080FF58

loc_8080FF28
MOV R0, R5
MOV R1, #0x3F
BL  __aeabi_uidivmod
ADD R2, SP, #0x58+var_18
ADD R5, R5, #1
ADD R7, R1, R7
ADD R3, R2, R1
LDRB    R2, [R7,#0x14]
RSB R10, R2, R10
MOV R2, #0
STRB    R10, [R3,#-0x40]
STRB    R2, [R3,#-0x3F]

loc_8080FF58
BL  getc
LDR R7, =asc_8082E770 ; "\b \b"
UXTB    R10, R0
CMP R10, #0xD   ; check if enter pressed
BNE loc_8080FF28
MOV R0, SP
ADD R1, R7, #0x54
MOV R2, #7
BL  sub_8081ECE4
CMP R0, #0
BNE loc_8080FF94
CMP R5, #7
MOVEQ   R5, #1
MOVEQ   R4, R0
BEQ loc_8080FFC0

loc_8080FF94
CMP R4, #3
BNE loc_8080FF10    ; fail after 3 tries
MOV R5, #0
MOV R4, R5
B   loc_8080FFC0

loc_8080FFA8
MOV R0, #0x2710
ADD R7, R7, #1
BL  sub_8081F1D8
CMP R7, #0x64
BNE loc_8080FEEC
SUB R4, R4, #1

loc_8080FFC0        ; "\b\b\b%2d "
LDR R0, =a2d
MOV R1, R4
BL  printf
; end of check passwd

sub_8081ECE4
STMFD   SP!, {R4,LR}
MOV R3, #0
B   loc_8081ED18

loc_8081ECF0
LDRB    R4, [R0,R3]
LDRB    R12, [R1,R3]
RSB R12, R12, R4
UXTB    R12, R12
CMP R12, #0
BNE loc_8081ED24
CMP R4, #0
ADD R3, R3, #1
BEQ loc_8081ED24
SUB R2, R2, #1

loc_8081ED18
CMP R2, #0
BNE loc_8081ECF0
MOV R12, R2

loc_8081ED24
SXTB    R0, R12
LDMFD   SP!, {R4,PC}
; End of function sub_8081ECE4
2个回答

例程 sub_8081ECE4 似乎从这个地址 0x8082e7c4 (R1=R7+0x54=0x8082e770+0x54) 中减去 7 个字节到堆栈上的数据(我假设这是输入的密码)。你能提供字节@0x8082e7c4吗?

编辑:黄色背景的块是某种解密程序,用字节表@0x8082e770 减去输入的字符。您需要仔细查看 SP+0x58+var18、SP+0x54 周围堆栈中发生的情况。Sub_8081ece4 是一个 strncmp 函数。我或多或少地用 C 转录:

// strncmp
int sub_8081ece4(char*str1, char *str2, int count) {
    for(int i=count, int j=0; i > 0; --count; ++j) {
        int cmp = str1[j] - str2[j];
        if( cmp != 0 || str1[j] == 0)
            return cmp;
    }
    return 0;
}

//...
// from loc_8080ff58
int i = 0;
char ch;
char var_18[0x3f]; // 0x58+var_18
char *tab; // ptr to 0x8082e770
while((ch = getch()) != 0xD) {
    int mod = i % 0x3f;
    ++i;
    var_18[mod - 0x40] = ch - tab[mod + 0x14];
    var_18[mod - 0x3f] = 0;
}

我现在设法找到了密码。

感谢 Tony 在他的回答中提供的 C 代码以及 Michael 在评论中提供的信息,我能够做出与原始密码类似的密码提示,并通过一些反复试验找到密码。

我还在实际硬件上测试了密码,并且能够进入 U-Boot shell。

这里是C程序供参考

#include <iostream>
#include <conio.h> // for getch

int main()
{
    int numOfTries = 1;

    char decTable[64] = { 0x23, 0x22, 0x02, 0x17, 0x0A, 0x0D, 0x07 }; // decryption table
    char passwd[8] = { 0x43, 0x4C, 0x24, 0x22, 0x2B, 0x25, 0x30, 0x0 }; // original, encrypted password

    // set rest of decTable to 0x0
    for (int j = 7; j < 64; j++)
        decTable[j] = 0x0;

    // reverse original password and show it
    char passwd_reversed[8] = { 0x0 };
    for (int k = 0; k < 7; k++)
    {
        int mod = k % 0x3f;
        passwd_reversed[k] = passwd[k] + decTable[mod];
    }

    printf("reversed password: %s\n\n", passwd_reversed);

    while (1)
    {
        printf("\n%dst input Passwd:", numOfTries);

        char inChar;
        int i = 0;
        char var_18[0x3f] = { 0x0 }; // encrypted user input

        char inStr[0x3f] = { 0x0 }; // original user input
        int inStrCounter = 0; // counter for current input character

        while (1)
        {
            inChar = getch();
            if (inChar == 0xD)
                break; // enter was pressed

            inStr[inStrCounter] = inChar;
            inStrCounter++;

            // Encrypt input char
            int mod = i % 0x3f;
            var_18[mod] = inChar - decTable[mod];
            i++;

            //var_18[mod - 0x40] = inChar - decTable[mod + 0x14];
            //var_18[mod - 0x3f] = 0;
        }

        // enter pressed, show input string and encrypted string
        printf("\nentered: %s  enc: %s\n", inStr, var_18);

        // verify password
        int cmp = strncmp(passwd, var_18, 7);
        if (cmp == 0)
        {
            printf("password OK\n");
            break;
        }
        else
            numOfTries++;
    }

    return 0;
}