Elevation of permission for devices read/dev by Android applications (2)In privilege escalation for devices in/dev for Android applications (1), two methods of privilege escalation are briefly summarized:
Device_initAnd
Init. RC. In this article, I will summarize in detail that it is easy to confuse people without being careful.
Init. c,
Device_initAnd
Init. RCHow do they work.
Directory structure ls: System/CORE/init/
Devices. c, Devices. H,
Init. c, Init. H, keywords. H, parser. C, property_service.c... In addition, system/CORE/rootdir/
Init. RCOf course, the location of init. RC can be specified separately.
The starting point of the INIT process is
Init. c: * The sequence number in the comment indicates the execution sequence.
Int main (INT argc, char ** argv ){...... Mkdir ("/dev", 0755); // create the basic file system node mkdir ("/proc", 0755); mkdir ("/sys", 0755 ); mount ("tmpfs", "/dev", "tmpfs", 0, "mode = 0755"); mkdir ("/dev/PTS", 0755 ); mkdir ("/dev/socket", 0755); mount ("devpts", "/dev/PTS", "devpts", 0, null); mount ("proc ", "/proc", "proc", 0, null); mount ("sysfs", "/sys", "sysfs", 0, null );...... Info ("reading config file \ n"); parse_config_file ("/init. RC "); // 1. Call the parse_config function to parse init. RC Script // 11, parsed, init. the RC content is divided into several segments, which are listed in the action_list linked list. The on starts with an action-type segment, such as the init segment. The init segment is represented by a struct action, where name is INIT, and all commands in this segment, are all strings in the commands linked list. Action_for_each_trigger ("early-init", action_add_queue_tail); // 12. traverse the action_list linked list to find the action whose name is early-init and put the node at the end of action_queu E. Drain_action_queue (); // 13. traverse the node at the end of action_queue and delete it. It is equivalent to traversing the commands linked list in the Action node whose name is early-init. All the commands in the on early-init section are executed in the init. RC Script....... Info ("device init \ n"); device_fd = device_init (); // common necessary device node property_init (); // The task after init is proper_service action_for_each_trigger ("init", action_add_queue_tail); // 14. Add the init segment to action_queue drain_action_queue (); // execute the command for init segment... ...}
System/CORE/init/parser. C:
Static void parse_config (const char * fN, char * s) {struct parse_state state; char * ARGs [maxargs]; int nargs; nargs = 0; State. filename = FN; State. line = 1; State. PTR = s; State. nexttoken = 0; State. parse_line = parse_line_no_op; // This function is empty, that is, it does not do anything for (;) {Switch (next_token (& State) {// 2. It works with the t_text status, put the parameters of each row in The args array first. Case t_eof: state. parse_line (& state, 0, 0); // Finally, the file is parsed and the previous section is complete. You need to write Null indicates the end. Return; Case t_newline: If (nargs) {int kW = lookup_keyword (ARGs [0]); // 3. Get a new row and start parsing, determine the keywords of the first parameter. The command, section, and option are available. This option is for services, enabling, disabling, and other operations. If (kw_is (kW, section) {// 4. Determine whether the obtained keyword is a segment. Keywords. h defines the attributes of various parsed keywords. State. parse_line (& state, 0, 0); // indicates that the resolution of the previous section ends, because a two-way linked list is used, so that null is written to the last element of the linked list, indicating that the end is reached. Parse_new_section (& state, KW, nargs, argS); // 5. Create a chain table of a new segment, such as the init segment. Jump to this function first, and then return.} Else {state. parse_line (& state, nargs, argS); // 10. Get a new row. You can see in the preceding operation the current section, whether it is on or service, the row parsing function has also changed accordingly. The line is parsed and added to the commands linked list of the action.} Nargs = 0;} break; Case t_text: If (nargs <maxargs) {ARGs [nargs ++] = state. text;} break ;}} void parse_new_section (struct parse_state * state, int kW, int nargs, char ** ARGs) {printf ("[% S % s] \ n", argS [0], nargs> 1? ARGs [1]: ""); Switch (kW) {// 6. determine the type of segment here. Different types of segments use different resolution functions, to put it bluntly, it is a command or service. Case k_service: State-> context = parse_service (State, nargs, argS); If (State-> context) {state-> parse_line = parse_line_service; return;} break; Case k_on: state-> context = parse_action (State, nargs, argS); // 7. Create an action linked list and add it to action_list if (State-> context) {state-> parse_line = parse_line_action; // 8. Replace the row parsing function. It turns out that parse_no_op does nothing and resolves each row into a command action. Add this command action to the commands linked list in the action: return;} break;} state-> parse_line = parse_line_no_op; // 9. An error occurs when the command is executed, the segment name is not written or too many are written}
Summary of this Chapter
After the above analysis, modification to/dev/Device Permissions will be overwritten in different locations, device. the modifications in C will overwrite the commands in Early-init, And the commands in init will overwrite device. c. If all three sets have the permission to use a device, the modification of the init segment will take effect.