Showing posts with label ARM. Show all posts
Showing posts with label ARM. Show all posts

Thursday, January 15, 2015

Practical Reverse Engineering p. 79 #10

Question number 10 on page 79 of Practical Reverse Engineering is as follows:

Figure 2-16 is a function from Windows RT. Read MSDN if needed. Ignore the security PUSH/POP cookie routines.

Here is the disassembly of the function:

Figure 2-16. Practical Reverse Engineering. © 2014 by Bruce Dang

 The ARM processor is in Thumb state, but transfers out during some of the syscalls. The function queries different clock APIs depending on the size of the supplied struct.

size_t QueryChrono(size_t *bytes_copied, 
                   size_t max_size, 
                   struct *clock_info)
{
    /* MOVS R4, #0 */
    bytes_copied = 0;

    /* CMP R5, #0x10 */
    if (max_size >= 16)
    {
        SYSTEMTIME sysTime;           /* SUB SP, SP, #0x10 */
        GetSystemTime(&sysTime);      /* LDR R3, =__imp_GetSystemTime */

        /* LDR R3, [SP,#0x1C+var_1C] */
        /* LDR R3, [SP,#0x1C+var_18] */
        /* LDR R3, [SP,#0x1C+var_14] */
        /* LDR R3, [SP,#0x1C+var_10] */
        /* STR R3, [R6,#0xC] */
        memcpy(clock_info->sysTime0x0, &sysTime, sizeof(SYSTEMTIME));

        bytes_copied = 16;              /* MOVS R4, #0x10 */
    }

    /* SUBS R3, R5, R4 */
    /* CMP R3, #4 */
    if ((max_size - bytes_copied) >= 4)
    {
        /* LDR R3, =__imp_GetCurrentProcessId */
        /* STR R0, [R6,R4] */
        *(clock_info + bytes_copied) = GetCurrentProcessId();

        bytes_copied += 4;              /* ADDS R4, #4 */
    }


    /* SUBS R3, R5, R4 */
    /* CMP R3, #4 */
    if ((max_size - bytes_copied) >= 4)
    {
        /* LDR R3, =__imp_GetTickCount */
        /* STR R0, [R6,R4] */
        *(clock_info + bytes_copied) = GetTickCount();

        bytes_copied += 4;              /* ADDS R4, #4 */
    }


    /* SUBS R3, R5, R4 */
    /* CMP R3, #9 */
    if ((max_size - bytes_copied) >= 8)
    {
        /* MOV R0, SP */
        LARGE_INTEGER perfCount;

        /* LDR R3, =__imp_QueryPerformanceCounter */
        QueryPerformanceCounter(&perfCount);

        /* STR R3, [R6,R4] */
        /* STR R3, [R2,#4] */
        memcpy((clock_info + bytes_copied), &perfCount,
                sizeof(LARGE_INTEGER));

        bytes_copied += 8;              /* ADDS R4, #8 */
    }

    return bytes_copied;                /* MOV R0, R4 */
}

Tuesday, January 13, 2015

Practical Reverse Engineering p. 79 #9

Question number 9 on page 79 of Practical Reverse Engineering is as follows:

What does the function shown in Figure 2-15 do?

Here is the function's disassembly:

Figure 2-15. Practical Reverse Engineering. © 2014 by Bruce Dang

The ARM processor is in Thumb state. This is essentially the same functionality as Figure 2-14, except the count variable is gone.

int32_t comparison(char *str1, char *str2)
{
    /* LDR R5, =byteArray */
    static BYTE byteArray[] = {0, 1, ..., 0xff};

    while(1)
    {
        /* CMP R4, #0 */
        if (*str1 == '\0')
            break;

        /* LDRB R3, [R1] */
        /* LDRB R4, [R3,R6] */
        /* LDRB R3, [R5,R6] */
        /* CMP R3, R4 */
        if (byteArray[*str1] != byteArray[*str2])
            break;

        ++str1;         /* ADDS R0, #1 */
        ++str2;         /* ADDS R1, #1 */
    }

    /* LDRB R2, [R3,R5] */   
    /* LDRB R3, [R3,R5] */
    /* SUBS R0, R3, R2 */
    return byteArray[*str1] - byteArray[*str2];   
}

Practical Reverse Engineering p. 79 #8

Question number 8 on page 79 of Practical Reverse Engineering is as follows:

In Figure 2-14, byteArray is a 256-character array whose content is byteArray[] = {0, 1, ..., 0xff}.

Here is the disassembly of the function:

Figure 2-14. Practical Reverse Engineering. © 2014 by Bruce Dang


The ARM processor is in Thumb state. We infer that this function takes two strings, as there is byte comparisons and the null byte ends the main loop. There is a 3rd argument which can terminate the main loop early as well. The function is a pretty straightforward translation to C.

int32_t comparison(char *str1, char *str2, uint32_t count)
{
    /* LDR R6, =byteArray */
    static BYTE byteArray[] = {0, 1, ..., 0xff};

    /* CMP R2, #0 */
    while (count > 0)
    {
        --count;    /* SUBS R2, #1 */

        /* LDRB R5, [R0] */
        /* CBZ R5, loc_100E352 */
        if (*str1 == '\0')
            break;

        /* LDRB R3, [R1] */
        /* LDRB R4, [R3,R6] */
        /* LDRB R3, [R5,R6] */
        /* CMP R3, R4 */
        if (byteArray[*str1] != byteArray[*str2])
            break;

        ++str1;     /* ADDS R0, #1 */
        ++str2;     /* ADDS R1, #1 */
    }

    /* SUBS R2, #1 */
    /* CMP R2, #0 */
    if ((count - 1) >= 0)
    {
        /* LDRB R2, [R3,R6] */   
        /* LDRB R3, [R3,R6] */
        /* SUBS R0, R3, R2 */
        return byteArray[*str1] - byteArray[*str2];    
    }

    return NULL;        /* MOVS R0, #0 */
}

Monday, January 12, 2015

Practical Reverse Engineering p. 79 #7

Question number 7 on page 79 of Practical Reverse Engineering is as follows:

Figure 2-13 illustrates a common routine, but you may not have seen it implemented this way.

Here is the disassembly of the function:

Figure 2-13. Practical Reverse Engineering. © 2014 by Bruce Dang


The ARM processor is in Thumb state. We immediately recognize this is a strlen() routine. There is a bit field clear at the end, whose purpose is unclear. Here is how the function is implemented:

size_t strlen(const char *str)
{
    /* CBNZ R0, loc_100E1D8 */
    if (r0 == NULL)
        return 0;   /* MOVS R0, #0 */

    /* MOV R2, R0 */
    char *index = str;
    
    while (1)               /* loc_100E1E4 */
    {
        /* CMB R3, #0 */
        if (*index == '\0')
            break;

        ++index;            /* ADDS R2, #1 */
    }

    /* SUBS R0, R2, R0 */
    return (index - str);
}

Practical Reverse Engineering p. 79 #6

Question number 6 on page 79 of Practical Reverse Engineering is as follows:

Figure 2-12 involves some twiddling.

Here is a disassembly of the function:

Figure 2-12. Practical Reverse Engineering. © 2014 by Bruce Dang


The ARM processor is in Thumb state. The function takes a struct that has a size value and array in it. The array is enumerated looking for a search value, then returning a type of bitmask on its location.

uint64_t search_mask(struct *r0, DWORD search)
{
    /* loc_103B3A8 */
    for (   
        DWORD i = 0;            /* MOVS R2, #0 */
        i < r0->numElements;    /* CMP R2, R4 */
        ++i;                    /* ADDS R2, #1 */
    )
    {
        /* LDR.W R3, [R0,#4]! */
        /* CMP R3, R1 */
        if (r0->elements[i] == search)
        {
            /* SUBS.W R3, R2, #0X20 */
            /* LSLS R1, R3 */
            search = 1 << (i - 0x20);

            /* MOVS R3, #1 */
            /* LSLS.W R0, R3, R2 */
            return (uint64_t) 1 << i;  
        }

    }

    search = 0; /* MOVS R1, #0 */
    return 0;   /* MOVS R0, #0 */
}

Here is a struct definition:

struct r0
{
    DWORD numElements;  /* 0x0 */
    DWORD elements[?];  /* 0x4 */
}

Practical Reverse Engineering p. 79 #5

Question number 5 on page 79 of Practical Reverse Engineering is as follows:

Figure 2-11 is simple as well. The actual string names have been removed so you cannot cheat by searching the Internet.

Here is the disassembly of the function:

Figure 2-11. Practical Reverse Engineering. © 2014 by Bruce Dang

The ARM processor is in Thumb state. This function can be written as a switch statement. It essentially takes an enum and returns a string based on the value.

const char *get_string(DWORD string_enum)
{
    /* MOV R3, R0 */
    switch (string_enum)
    {
        case 6:             /* CMP R3, #6 */
            return "E";     /* LDR R0, =aE ; "E" */

        case 7:             /* CMP R3, #7 */
            return "D";     /* LDR R0, =aD ; "D" */

        case 8:             /* CMP R3, #8 */
            return "C";     /* LDR R0, =ac ; "C" */

        case 9:             /* CMP R3, #9 */
            return "B";     /* LDR R0, =aB ; "B" */

        default:
            return "A";     /* LDR R0, =aA ; "A" */ 
    }
}

Practical Reverse Engineering p. 79 #4

Question number 4 on page 79 of Practical Reverse Engineering is as follows:

Figure 2-10 shows another easy function.

Here is the function's disassembly:

Figure 2-10. Practical Reverse Engineering. © 2014 by Bruce Dang


The ARM processor is in Thumb state. This function takes a pointer of an unknown type. If the pointer is null, it returns 0. Otherwise it subtracts 8 bytes from the pointer and returns the value there.

DWORD sub8_ptr(void *r0)
{
    /* CBNZ R0, loc_100C3DA */
    if (r0 == NULL)
        return 0;       /* MOVS R0, #0 */

    return *(r0 - 8);   /* LDR.W R0, [R0,#–8]  */
}

Practical Reverse Engineering p. 79 #3

Question number 3 on page 79 of Practical Reverse Engineering is as follows:

Here is a simple function:

01: mystery3
02: 83 68 LDR R3, [R0,#8]
03: 0B 60 STR R3, [R1]
04: C3 68 LDR R3, [R0,#0xC]
05: 00 20 MOVS R0, #0
06: 4B 60 STR R3, [R1,#4]
07: 70 47 BX LR
08: ; End of function mystery3

The ARM processor is in Thumb state. This function just copies some values from the first struct to the second struct. It always returns 0.

int copy_struct_values(struct *r0, struct *r1)
{
    /* LDR R3, [R0,#8] */
    /* STR R3, [R1] */
    r1->Unknown0x0 = r0->Unknown0x8;                

    /* LDR R3, [R0,#0xC] */   
    /* STR R3, [R1,#4] */
    r1->Unknown0x4 = r0->Unknown0xc;

    return 0;   /* MOVS R0, #0 */
}

Here are the struct definitions:

struct r0
{
    BYTE Unknown0x0[0x8];   /* 0x0 */
    DWORD Unknown0x8;       /* 0x8 */
    DWORD Unknown0xc;       /* 0xc */
}

struct r1
{
    DWORD Unknown0x0;   /* 0x0 */
    DWORD Unknown0x4;   /* 0x4 */
}

Practical Reverse Engineering p. 78 #2

Question number 2 on page 78 of Practical Reverse Engineering is as follows:

Figure 2-9 shows a function that was found in the export table.

Here is the function's disassembly:

Figure 2-9. Practical Reverse Engineering. © 2014 by Bruce Dang


 We can immediately tell the ARM processor should be in Thumb state. This function checks if the struct passed is NULL. If it is not, then one of the members is checked to see if the byte equals 0.

BOOL check_struct_char(struct *r0)
{
    /* CBZ R0, loc_C672 */
    if (r0 != NULL)
    {    
        /* LDRB.W R0, [R0,#0x63] */
        /* SUBS R0, #0 */
        if (r0->Unknown0x63 == 0)
            return FALSE; 
    }  

    return TRUE;           /* MOVS R0, #1 */
}

And here is a definition of the passed struct:

struct r0
{
    BYTE Unknown0x0[0x63];  /* 0x0 */
    CHAR Unknown0x63;       /* 0x63 */
}

Practical Reverse Engineering p. 78 #1

Question number 1 on page 78 of Practical Reverse Engineering is as follows:

Figure 2-8 shows a function that takes two arguments. It may seem somewhat challenging at fi rst, but its functionality is very common. Have patience.

Indeed the disassembly does appear to be a reasonably complex function.

Figure 2-8. Practical Reverse Engineering. © 2014 by Bruce Dang

This function is not in Thumb state as every instruction is 32-bits in width. It attempts to convert an ASCII string to a signed decimal number. It is very lenient as far as input (even accepting non-numerical characters in the string input), however it will not work on strings exceeding the MAX_INT constant of 2147483648 (0x80000000).

Here is a close 1 to 1 approximation from ARM to C:
 
BOOL ascii_to_decimal(const char *str, int32_t *retNum)
{
    BOOL negative;
    int i = 0;              /* LDRB R3, [R0] */

    /* CMP R3, #0x2D */
    if  (str[i] == '-')
    {
        ++i;                /* LDRB R3, [R0,#1]! */
        negative = TRUE;    /* MOV R6, #1 */
    }
    else 
    {
        negative = FALSE;   /* MOV R6, #0 */

        /* CMP R3, #0x2B */
        if (str[i] == '+')
            ++i;            /* LDREQB R3, [R0,#1]! */
    }

    /* CMP R3, #0x30 */
    if (str[i] == '0')
    {
        /* CMP R2, #0x30 */
        while (str[i] == '0')
            ++i;            /* LDRB R2, [R3],#1 */    
    }

    const int base = 10;    /* MOV R8, #0xA */
    int64_t result = 0;

    while (TRUE)
    {    
        result *= base;         /* UMULL R2, R3, R4, R8 */
        result += str[i] - '0'; /* ADDS R4, R2, R7 */
        ++i;                    /* ADD R12, R12, #1 */

        /* SUBS R7, R7, #0x30 */
        if (str[i] < '0')
            break;

        /* CMP R7, #9 */
        if (str[i] > '9')
            break;
    }

    /* CMP R2, #0x80000000 */
    if (abs((int32_t) result) > INT_MAX)
        return FALSE;               /* MOV R0, #0 */

    *retNum = (int32_t) result;     /* STR R4, [R1] */
    return TRUE;                    /* MOV R0, #1 */
}

Sunday, December 28, 2014

Hex/Binary Pebble Watchface

My girlfriend got me the Pebble Steel smart watch for Christmas. The watch runs on an ARM Cortex M3 with a modified FreeRTOS kernel (which is described more as a threading library than a traditional operating system).

When I get a device like this I always have to poke around the API and see what it has to offer. So I looked at the getting started guide and wrote an app that simply displays the time and date in hexadecimal and binary forms.


The API is in C, and you only have access to a subset of the standard library. For instance, instead of doing itoa() with a base of two to display the numbers as binary, I had to create the following monstrosity:

const char *bytebin(int n, int m, char *b, int l)
{
    for (b[0] = '\0'; m > 0 && l > 0; m >>= 1, --l)
        strcat(b, ((n & m) == m) ? "1" : "0");
  
    return b;
}

And this is how I use it:

    snprintf(binDateBuffer, sizeof(binDateBuffer), "%s/%s/%s", 
           bytebin(tick_time->tm_mon + 1, 0x8, binMon, 4), 
           bytebin(tick_time->tm_mday, 0x10, binDay, 5), 
           bytebin(tick_time->tm_year + 1900, 0x400, binYr, 11));

The development IDE is hosted in the cloud. You literally just type in some C code and press play. The web application then compiles it and uploads it to your phone which sends it to the watch via Bluetooth. This lets you jump right into developing without any setup.