📜 ⬆️ ⬇️

ELF - an application on your LG phone?

Initial opinion


I always thought that LG’s phones were for housewives. And when the LG KP500 came into my hands, I didn’t change my opinion, although there was a lot of very interesting things about it. I mean, this is the task manager (there is even a special button) that can call and close other collapsed native and Java applications. In Java, work with the file system (JSR - 75) is available, though not completely, with this Java functionality. is ending. This phone (I emphasize this, it is positioned as a "dialer") even has its own format of executive files - PXE (* .pxo), but the truth is, it is hidden for the user and starts from a specific folder on the disk, having a read-only attribute. This unit has a good “iron”. These are Nand Flash 256 MB / SDRAM 128 MB, TFT touch resistive display with a resolution of 400x240 and 262 thousand colors, a 3-axis accelerometer and a baseband Infineon SGold-3 processor (PMB8877), and a standard set: camera, BlueTooth, radio and etc. An operating system such as Android, Windows, iOS is not there, but there is a closed “bicycle” on the Nucleus RTOS core of the ancient version. Such a “iron”, in my opinion, did not come across to the underground “elf descriptors,” which gives a certain incentive.

PXE format


PXE is the format of executable files on LG phones starting at KP500. It, you guessed it, is closed, there is no documentation on it, I’m generally silent about the SDK. The phone runs only from the system disk directory firmware or other native applications of this format:

"/cus/lgapp/Pxo/*.pxo"

Since the processor is in the ARM926EJ-S phone, the ARM / Thumb instructions are also found in them.
These files have a “Place Independed Code”, i.e. do not depend on the address of loading, that is projection on memory. This suggests that there is a relocation table. Written, of course, on ARM C / C ++, but still, developers preferred the Thumb set of instructions. There are 2 sections: data and code. Of course, PXE applications use some API. It is represented by a 2-level library of functions, well, by a group of tables of pointers to firmware procedures. A pointer to this table is reported to the application upon creation. But the program itself is built on the main event handler, i.e. it receives various events: create, exit, stop, activate, redraw, timer, etc.
')

ELF - loader


It was possible to create programs in PXE files, but for this you need, at a minimum, a linker who can collect it from object files, where it is unknown to get such, and writing is death itself. The second factor is the limitation of the launch site, not just a restriction, but a whole problem, because just to add it to the system disk catalog is a tedious task and the disk is not rubber, although you can cope with it without difficulty and tearing your hair.
It remains the original way - to make their programs in ELF format. Writing a bootloader for it is a simple task, but compilers who can collect it are more than enough.
So I decided to write an elf downloader for this phone, there were no problems inserting my code into the firmware. Oh yeah, about the firmware modification, it’s very strange that no one has been doing this for 4 years. The community created / unblocked / got out any flash themes, programs for unpacking / collecting firmware, official flash drivers, utilities, even a flasher to merge / FS flooding (unfortunately, the writing / reading of code areas was done incorrectly, therefore it is useless). Those. There were a lot of achievements, but in terms of patching and researching the firmware code, a little more was done than nothing. I had to independently study the program for the processor test, I found in it the secret protocol (DWD) for working with the phone, wrote the program, simultaneously correcting the glitches of this protocol, and finally merged all the necessary dumps of the address space. So back to our elves. The modified firmware can run one elf, and he, in turn, loads the rest of the elves and the library, as well as patches Java - the machine to expand its capabilities. Everything is fine, but loaded elves are just bare code projected into memory. And so that the phone sees in them a normal program, it was decided to use the “parasitizing” method of the PXE file. For this, a small file of this format was patched; he began to redirect all events to ELF, which uploaded it, and cleared it from memory at the exit event. The elf was required to download this “donor.pxo” with the parameters - pointers to the event handling procedure and the download base and to copy the code that is presented in the PXE executable files. Elves still have the ability to use procedure calls via SWI, i.e. separate function library and SWI handler, as in ElfPack at Siemens.

This is how the code of the elf looks like:

main.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include "elf/elf.h" extern int thing_w; extern int thing_h; extern int thing_d; extern unsigned char thing_bitmap[]; extern int star_w; extern int star_h; extern int star_d; extern unsigned char star_bitmap[]; /* =================================== GUI ================================== */ #define WINDOW_ID_SCREEN 0x5001 int Screen_EventHandler(int event_id, int item_num, int param); void Screen_OnInit(); void Screen_Close(int action); void Screen_OnExit(); void Screen_OnKeyDown(int key); void Screen_OnKeyUp(int key); void Screen_OnDraw(); void Screen_OnIndicatorDraw(); void Screen_OnTimer(); void Screen_OnPointing(int action, int position); void Screen_OnAwake(); void Screen_OnSleep(); int x1 = 0, y1 = 0, x2 = 0, y2 = 0; int w1 = 0, h1 = 0, w2 = 0, h2 = 0; int z = 0, d = 0; unsigned char *b1 = 0, *b2 = 0; int de1 = 0, de2 = 0; void Draw() { char ascii_text_buffer[256]; unsigned short u16_text_buffer[256]; drw_fillrect(0, GUI_STATUSBAR_HEIGHT, DISPLAY_WITDH, DISPLAY_HEIGHT, drw_color_make_rgb(0, 0, 0)); drw_string_setoutline(1); drw_string_setcolor(drw_color_make_rgb(200, 0, 0)); cp1251_2_utf16(u16_text_buffer, " "); drw_string(0, GUI_STATUSBAR_HEIGHT + 16 * 0, u16_text_buffer, 16); sprintf(ascii_text_buffer, " #1: X: %d / Y: %d", x1 + w1/2, y1 + h1/2); cp1251_2_utf16(u16_text_buffer, ascii_text_buffer); drw_string(0, GUI_STATUSBAR_HEIGHT + 16 * 1, u16_text_buffer, 16); sprintf(ascii_text_buffer, " #2: X: %d / Y: %d", x2 + w2/2, y2 + h2/2); cp1251_2_utf16(u16_text_buffer, ascii_text_buffer); drw_string(0, GUI_STATUSBAR_HEIGHT + 16 * 2, u16_text_buffer, 16); if (z == 1) { drw_bitmap(x1, y1, w1, h1, de1, b1); drw_bitmap(x2, y2, w2, h2, de2, b2); } else { drw_bitmap(x2, y2, w2, h2, de2, b2); drw_bitmap(x1, y1, w1, h1, de1, b1); } gui_redraw(); } //    void Screen_OnInit() { printf("Screen_OnInit\r\n"); x1 = 50; x2 = 80; y1 = 200; y2 = 50; w1 = thing_w; h1 = thing_h; w2 = star_w; h2 = star_h; b1 = thing_bitmap; b2 = star_bitmap; de1 = thing_d; de2 = star_d; z = 0; d = 0; Draw(); } //    void Screen_OnExit() { printf("Screen_OnExit\r\n"); } //         void Screen_OnKeyDown(int key) { printf("Screen_OnKeyDown key = %d\r\n", key); switch (key) { case KEY_MULTI: __taskapi_call_taskman(); break; case KEY_END: __taskapi_app_exit(0, 0, 0); break; } Draw(); } //     void Screen_OnKeyUp(int key) { printf("Screen_OnKeyUp key = %d\r\n", key); } //    void Screen_OnDraw() { //printf("Screen_OnDraw()\r\n"); Draw(); } //   - void Screen_OnIndicatorDraw() { //printf("Screen_OnIndicatorDraw()\r\n"); Draw(); } //    void Screen_OnTimer(int timer_id, int param) { //printf("Screen_OnTimer: %d / %d\r\n", timer_id, param); } //     void Screen_OnPointing(int action, int position) { int x, y; x = PXE_LOWORD(position); y = PXE_HIWORD(position); switch (action) { case TOUCH_ACTION_PRESS: { // 1-   if (z == 0) { if (x >= x1 && x < (x1 + w1) && y >= y1 && y < (y1 + h1)) d = 1; else { if (x >= x2 && x < (x2 + w2) && y >= y2 && y < (y2 + h2)) { z = 1; d = 1; } } // 2-   } else { if (x >= x2 && x < (x2 + w2) && y >= y2 && y < (y2 + h2)) d = 1; else { if (x >= x1 && x < (x1 + w1) && y >= y1 && y < (y1 + h1)) { z = 0; d = 1; } } } break; } case TOUCH_ACTION_PRESSED: { if (d == 1) { if (z == 0) { x1 = x; y1 = y; } else { x2 = x; y2 = y; } } break; } case TOUCH_ACTION_RELEASE: { d = 0; break; } } Draw(); } //   void Screen_OnAwake() { printf("Screen_OnAwake()\r\n"); } //   void Screen_OnSleep() { printf("Screen_OnSleep()\r\n"); } //   WINDOW_ID_MAINMENU   int Window_EventHandler(int cmd, int subcmd, int status) { switch (cmd) { case Window_OnInit: Screen_OnInit(); break; case Window_OnExit: Screen_OnExit(); break; case Window_OnAwake: Screen_OnAwake(); break; case Window_OnSleep: Screen_OnSleep(); break; case Window_OnKeyDown: Screen_OnKeyDown(subcmd); break; case Window_OnKeyUp: Screen_OnKeyUp(subcmd); break; case Window_OnDraw: Screen_OnDraw(); break; case Window_OnTimer: Screen_OnTimer(subcmd, status); break; case Window_OnPointing: Screen_OnPointing(subcmd, status); break; case Window_OnIndicatorDraw: Screen_OnIndicatorDraw(); break; default: break; } return 1; } /* ----------------------    --------------------- */ int elf_run(int event_id, int wparam, int lparam) { //printf("elf_run = %d / %d / 0x%08X\r\n", event_id, wparam, lparam); switch (event_id) { //    case PXE_RUN_CREATE_EVENT: //      __taskapi_app_setname(app_handle, 0, 0, 0); //  gui_window_create(WINDOW_ID_SCREEN, Window_EventHandler); //   gui_window_init(WINDOW_ID_SCREEN); printf("PXE_RUN_CREATE_EVENT\r\n"); return 1; //    case PXE_RUN_DESTROY_EVENT: //  gui_window_destroy_all(); printf("PXE_RUN_DESTROY_EVENT\r\n"); return 1; //    case PXE_RUN_RESUME_EVENT: printf("PXE_RUN_RESUME_EVENT\r\n"); //    gui_window_trans_event(PXE_RUN_PAINT_EVENT, 0, 0); return 1; //    case PXE_RUN_SUSPEND_EVENT: printf("PXE_RUN_SUSPEND_EVENT\r\n"); return 1; default: //      gui_window_trans_event(event_id, wparam, lparam); return 1; } } 



The first is not a test elf, which I publicly introduced, this is the Sega prefix emulator.


Direct link to the video

And everything else on the topic:
Best practices for KP500

Source: https://habr.com/ru/post/155289/


All Articles