adb 工具源码修改
1、修改客户端输入后的判断逻辑,使带密码的命令 可以通过命令检查
修改 system/core/adb/client/commandline.cpp
在最前面 新增一个函数 用来处理 自定义带密码的命令
//add by dk start
std::string get_command(const char* c){
std::string s= c;
if(s.find("-") != std::string::npos){
char buf[20];
strcpy(buf,s.c_str());
char* str1= strtok(buf, " -");
fprintf(stderr, "adb:strock----\"%s\"\n", str1);
return str1;
}
char * p=(char*)s.c_str();
fprintf(stderr, "adb:buf****----\"%s\"\n", p);
return s;
}
//add by dk end
对 adb_commandline(int argc, const char** argv) 函数内容进行修改 此函数 是对adb 命令进行校验 和处理
argv 是输入的命令和参数 数组 argv[0] 表示的是 命令字段
//add by dk start
//获取处理后的命令
fprintf(stderr, "adb:--command--\"%s\"\n", argv[0]);
std::string str1=get_command(argv[0]);
fprintf(stderr, "adb:get_command----\"%s\"\n", str1.c_str());
//add by dk end
//add by dk
//修改root 命令判断,用处理后的命令匹配
else if (!strcmp(str1.c_str(), "root") || !strcmp(argv[0], "unroot")){
return adb_root(argv[0]) ? 0 : 1;
}
//修改shell 命令判断,用处理后的命令匹配
else if (!strcmp(str1.c_str(), "shell")) {
return adb_shell(argc, argv);
}
//修改push pull 命令判断,用处理后的命令匹配
else if (!strcmp(str1.c_str(), "push")) {
bool copy_attrs = false;
bool sync = false;
bool compressed = true;
std::vector<const char*> srcs;
const char* dst = nullptr;
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync, &compressed);
if (srcs.empty() || !dst) error_exit("push requires an argument");
//return do_sync_push(srcs, dst, sync, compressed) ? 0 : 1;
//add by dakun
std::string pass_s=argv[0];
auto sub = pass_s+":";
fprintf(stderr, "adb:push----\"%s\"\n", sub.c_str());
return do_sync_push(srcs, dst, sync, compressed,sub.c_str()) ? 0 : 1;
//add end
} else if (!strcmp(str1.c_str(), "pull")) {
bool copy_attrs = false;
bool compressed = true;
std::vector<const char*> srcs;
const char* dst = ".";
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr, &compressed);
if (srcs.empty()) error_exit("pull requires an argument");
//return do_sync_pull(srcs, dst, copy_attrs, compressed) ? 0 : 1;
//add by dakun
std::string pass_s=argv[0];
auto sub = pass_s+":";
return do_sync_pull(srcs, dst, copy_attrs,compressed, sub.c_str(),nullptr) ? 0 : 1;
//add end
}
在命令后都会调用 adb_connect()方法去进行与服务端通信,但是 shell 和push pull 命令 会进行进一步处理。
对 shell 命令进行追踪处理
修改adb_shell(int argc, const char** argv) 方法
在方法的最后 通过调用 RemoteShell 来进一步调用 adb_connect ,发现 在进行 adb_connect 时所传递的service_string 是 ShellServiceString 方法生成的
//std::string service_string = ShellServiceString(use_shell_protocol, shell_type_arg, command); //add by dakun std::string service_string = ShellServiceString(use_shell_protocol, shell_type_arg, command,sp.c_str()); return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command.empty(),service_string);
在 ShellServiceString 方法中可以看到 service_string 方是通过StringPrintf 进行拼接 ,
在这里需要重载一个 ShellServiceString 方法将 带密码的shell 传入 拼接到一起。
//add by dakun static std::string ShellServiceString(bool use_shell_protocol, const std::string& type_arg, const std::string& command, const std::string& pass) { std::vector<std::string> args; if (use_shell_protocol) { args.push_back(kShellServiceArgShellProtocol); const char* terminal_type = getenv("TERM"); if (terminal_type != nullptr) { args.push_back(std::string("TERM=") + terminal_type); } } if (!type_arg.empty()) { args.push_back(type_arg); } // Shell service string can look like: shell[,arg1,arg2,...]:[command]. return android::base::StringPrintf("%s%s%s:%s", pass.c_str(), args.empty() ? "" : ",", android::base::Join(args, ',').c_str(), command.c_str()); }
在 adb_shell(int argc, const char** argv) 中 会对argv[0] 重新赋值,所以在最开始要先获取传入的密码
//add by dakun std::string sp=argv[0]; fprintf(stderr, "adb:strcat----\"%s\"\n", sp.c_str()); // Parse shell-specific command-line options. argv[0] = "adb shell"; // So getopt(3) error messages start "adb shell".
对push 和 pull 命令进行追踪处理
push 和 pull 命令都是通过 sync 命令同步实现的
在匹配命令之后最终会调用 do_sync_push和 do_sync_pull 这两个方法来执行上传
通过追踪 发现这是在file_sync_client.cpp 中的方法
在这两个方法中能找到 SyncConnection 类 ,追踪这个类的构造可以发现 在这个构造方法中进行了
adb_connect(“sync-”, &error) ,所以想要将密码传入需要 新增一个带参数的构造用来传密码
//add by dakun public: SyncConnection(std::string_view s) : acknowledgement_buffer_(sizeof(sync_status) + SYNC_DATA_MAX) { acknowledgement_buffer_.resize(0); max = SYNC_DATA_MAX; // TODO: decide at runtime. std::string error; if (!adb_get_feature_set(&features_, &error)) { Error("failed to get feature set: %s", error.c_str()); } else { have_stat_v2_ = CanUseFeature(features_, kFeatureStat2); have_ls_v2_ = CanUseFeature(features_, kFeatureLs2); have_sendrecv_v2_ = CanUseFeature(features_, kFeatureSendRecv2); have_sendrecv_v2_brotli_ = CanUseFeature(features_, kFeatureSendRecv2Brotli); fd.reset(adb_connect(s, &error)); if (fd < 0) { Error("connect failed: %s", error.c_str()); } } } //add end
同样也新增一个带密码参数的 do_sync_push 或 do_sync_pull 方法 ,在这个方法中调用 带参数的
SyncConnection(std::string_view s) 构造方法
//add by dakun bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync, bool compressed,const char* pass) { SyncConnection sc(pass); if (!sc.IsValid()) return false; bool success = true; bool dst_exists; bool dst_isdir; struct stat st; if (sync_stat_fallback(sc, dst, &st)) { dst_exists = true; dst_isdir = S_ISDIR(st.st_mode); } else { if (errno == ENOENT || errno == ENOPROTOOPT) { dst_exists = false; dst_isdir = false; } else { sc.Error("stat failed when trying to push to %s: %s", dst, strerror(errno)); return false; } } if (!dst_isdir) { if (srcs.size() > 1) { sc.Error("target '%s' is not a directory", dst); return false; } else { size_t dst_len = strlen(dst); // A path that ends with a slash doesn't have to be a directory if // it doesn't exist yet. if (dst[dst_len - 1] == '/' && dst_exists) { sc.Error("failed to access '%s': Not a directory", dst); return false; } } } for (const char* src_path : srcs) { const char* dst_path = dst; struct stat st; if (stat(src_path, &st) == -1) { sc.Error("cannot stat '%s': %s", src_path, strerror(errno)); success = false; continue; } if (S_ISDIR(st.st_mode)) { std::string dst_dir = dst; // If the destination path existed originally, the source directory // should be copied as a child of the destination. if (dst_exists) { if (!dst_isdir) { sc.Error("target '%s' is not a directory", dst); return false; } // dst is a POSIX path, so we don't want to use the sysdeps // helpers here. if (dst_dir.back() != '/') { dst_dir.push_back('/'); } dst_dir.append(android::base::Basename(src_path)); } success &= copy_local_dir_remote(sc, src_path, dst_dir, sync, false, compressed); continue; } else if (!should_push_file(st.st_mode)) { sc.Warning("skipping special file '%s' (mode = 0o%o)", src_path, st.st_mode); continue; } std::string path_holder; if (dst_isdir) { // If we're copying a local file to a remote directory, // we really want to copy to remote_dir + "/" + local_filename. path_holder = dst_path; if (path_holder.back() != '/') { path_holder.push_back('/'); } path_holder += android::base::Basename(src_path); dst_path = path_holder.c_str(); } sc.NewTransfer(); sc.SetExpectedTotalBytes(st.st_size); success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode, sync, compressed); sc.ReportTransferRate(src_path, TransferDirection::push); } success &= sc.ReadAcknowledgements(true); sc.ReportOverallTransferRate(TransferDirection::push); return success; } //add end
ps:这里传的是 push 和 pull 而不是之前的sync 所以在服务端也要进行处理 ,并且需要同步修改
file_sync_client.h 文件
//add by dakun bool do_sync_push(const std::vector<const char*>& srcs, const char* dst, bool sync, bool compressed,const char* pass); bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs, bool compressed, const char* pass, const char* name = nullptr); //add by end