本合集共7部分,本篇为第三部分
根据这些头文件,看起来它们提供了一种非常方便的方式与车辆进行交互,提供了查询里程表、电池电压等信息的函数,以及执行启动发动机或锁定/解锁车门等操作的功能。
在名为 HBody.h 的一个 ccOS 头文件中,包含了类 HBody。HBody 是一个单例类,其中包含一个静态方法来获取 HBody 的实例。HBody 本身包含一个名为 isDoorOpened 的方法,用于判断特定门是开着还是关着。
HBody 中的所有查询函数都返回一个 HResult,指示它是否成功查询了对象,或者是什么错误阻止了查询。每个查询方法还接受一个输出类型的引用,以提供实际的查询结果。
isDoorOpened 函数接受一个 HDoorPosition 枚举来指定你要查看的门是开着还是关着(前左/右、后左/右或尾门),以及一个 HTriState 的引用,用于指示门是否打开(False、True、Invalid)。
以下是我编写的代码:
#include <iostream>#include <vector>#include <string>#include "HBody.h"using namespace std;const char* HResultToString(ccos::HResult result){switch (result){case ccos::HResult::INVALID:return "INVALID";case ccos::HResult::OK:return "OK";case ccos::HResult::ERROR:return "ERROR";case ccos::HResult::NOT_SUPPORTED:return "NOT_SUPPORTED";case ccos::HResult::OUT_OF_RANGE:return "OUT_OF_RANGE";case ccos::HResult::CONNECTION_FAIL:return "CONNECTION_FAIL";case ccos::HResult::NO_RESPONSE:return "NO_RESPONSE";case ccos::HResult::UNAVAILABLE:return "UNAVAILABLE";case ccos::HResult::NULLPOINTER:return "NULLPOINTER";case ccos::HResult::NOT_INITIALIZED:return "NOT_INITIALIZED";case ccos::HResult::TIMEOUT:return "TIMEOUT";case ccos::HResult::PERMISSION_DENIED:return "PERMISSION_DENIED";case ccos::HResult::ALREADY_EXIST:return "ALREADY_EXIST";case ccos::HResult::SOME_UNAVAILABLE:return "SOME_UNAVAILABLE";case ccos::HResult::INVALID_RESULT:return "INVALID_RESULT";case ccos::HResult::MAX:return "MAX";default:return "Other";}}int main(){cout << "Ioniq Test Application";cout << endl;ccos::vehicle::general::HBody *body = ccos::vehicle::general::HBody::getInstance();ccos::vehicle::HTriState doorState;ccos::HResult doorOpenedResult = body->isDoorOpened(ccos::vehicle::HDoorPosition::FRONT_LEFT, doorState);if (doorOpenedResult == ccos::HResult::OK) {cout << "Door Result: " << (doorState == ccos::vehicle::HTriState::TRUE ? "Open" : "Closed");cout << endl;} else {cout << "isDoorOpened did not return OK. Actual return: " << HResultToString(doorOpenedResult);cout << endl;}cout << "Finished door test";cout << endl;}
All I had to do is… (Don’t do this)
我启动了反向 shell,将二进制文件复制到 /tmp/ 目录,将其标记为可执行,并运行了它。
#include <iostream>#include <string>#include "HBody.h"#include "HChassis.h"using namespace std;namespace ccOSUtils{const char *HTriStateToString(ccos::vehicle::HTriState state){switch (state){case ccos::vehicle::HTriState::FALSE:return "False";case ccos::vehicle::HTriState::TRUE:return "True";case ccos::vehicle::HTriState::INVALID:return "INVALID";case ccos::vehicle::HTriState::MAX:return "MAX";default:return "Other";}}const char *HResultToString(ccos::HResult result){switch (result){case ccos::HResult::INVALID:return "Invalid";case ccos::HResult::OK:return "OK";case ccos::HResult::ERROR:return "ERROR";case ccos::HResult::NOT_SUPPORTED:return "NOT_SUPPORTED";case ccos::HResult::OUT_OF_RANGE:return "OUT_OF_RANGE";case ccos::HResult::CONNECTION_FAIL:return "CONNECTION_FAIL";case ccos::HResult::NO_RESPONSE:return "NO_RESPONSE";case ccos::HResult::UNAVAILABLE:return "UNAVAILABLE";case ccos::HResult::NULLPOINTER:return "NULLPOINTER";case ccos::HResult::NOT_INITIALIZED:return "NOT_INITIALIZED";case ccos::HResult::TIMEOUT:return "TIMEOUT";case ccos::HResult::PERMISSION_DENIED:return "PERMISSION_DENIED";case ccos::HResult::ALREADY_EXIST:return "ALREADY_EXIST";case ccos::HResult::SOME_UNAVAILABLE:return "SOME_UNAVAILABLE";case ccos::HResult::INVALID_RESULT:return "INVALID_RESULT";case ccos::HResult::MAX:return "MAX";default:return "Other";}}}int main(int argc, char *argv[]){cout << "Ioniq Advanced Test Application" << endl;if (argc == 1){cout << "Provide at least 1 argument (doorStatus, doorLock, status, test)" << endl;return 0;}ccos::vehicle::general::HBody *body = ccos::vehicle::general::HBody::getInstance();string command = argv[1];if (command == "doorStatus"){if (argc != 3){cout << "Expected arguments: doorStatus {fl/fr/rl/rr}" << endl;return 0;}string doorStr = argv[2];ccos::vehicle::HDoorPosition doorPosition = ccos::vehicle::HDoorPosition::FRONT_LEFT;if (doorStr == "fl"){doorPosition = ccos::vehicle::HDoorPosition::FRONT_LEFT;}else if (doorStr == "fr"){doorPosition = ccos::vehicle::HDoorPosition::FRONT_RIGHT;}else if (doorStr == "rl"){doorPosition = ccos::vehicle::HDoorPosition::REAR_LEFT;}else if (doorStr == "rr"){doorPosition = ccos::vehicle::HDoorPosition::REAR_RIGHT;}ccos::vehicle::HTriState doorState;ccos::HResult doorOpenedResult = body->isDoorOpened(doorPosition, doorState);if (doorOpenedResult == ccos::HResult::OK){cout << "Door Result: " << (doorState == ccos::vehicle::HTriState::TRUE ? "Open" : "Closed");cout << endl;}else{cout << "isDoorOpened did not return OK. Actual return: " << ccOSUtils::HResultToString(doorOpenedResult);cout << endl;}}else if (command == "doorLock"){if (argc != 3){cout << "Expected arguments: doorLock {true/false}" << endl;return 0;}string shouldBeLockedStr = argv[2];ccos::HBool shouldBeLocked = false;if (shouldBeLockedStr[0] == 't'){shouldBeLocked = true;}cout << "Setting Door Locks to: " << (shouldBeLocked ? "Locked" : "Unlocked") << endl;ccos::HResult doorLockResult = body->requestDoorLock(shouldBeLocked);if (doorLockResult == ccos::HResult::OK){cout << "Door Lock Success" << endl;}else{cout << "Door Lock Failure: " << ccOSUtils::HResultToString(doorLockResult) << endl;}}else if (command == "status"){ccos::vehicle::general::HChassis *chassis = ccos::vehicle::general::HChassis::getInstance();ccos::HFloat odometerReading = 0;chassis->getOdometer(odometerReading);ccos::HFloat batteryVoltage = 0;chassis->getBatteryVoltage(batteryVoltage);ccos::HUInt8 percentBatteryRemaining = 0;chassis->getRemainBattery(percentBatteryRemaining);cout << "Vehicle Status:" << endl;cout << "tOdometer: " << odometerReading << endl;cout << "tBattery Voltage: " << batteryVoltage << "V" << endl;cout << "tBattery Remaining: " << percentBatteryRemaining << "%" << endl;}else if (command == "test"){cout << "Testing methods that might not work" << endl;ccos::HResult testResult;cout << "tTesting Wireless Charging Pad State" << endl;ccos::HUInt8 wirelessChargingPadState = 0;testResult = body->getWirelessChargingPadState(wirelessChargingPadState);cout << "tt" << ccOSUtils::HResultToString(testResult) << " - State: " << wirelessChargingPadState << endl;cout << "tTesting Window State (Driver)" << endl;ccos::vehicle::HWindowType windowType = ccos::vehicle::HWindowType::DRIVER;ccos::vehicle::HTriState windowState;ccos::HUInt8 windowDetail;body->getWindowOpenState(windowType, windowState, windowDetail);cout << "tt" << ccOSUtils::HResultToString(testResult) << " - State: " << ccOSUtils::HTriStateToString(windowState) << "Detail?: " << windowDetail << endl;cout << "Completed testing methods that might not work" << endl;}else{cout << "Unknown Command" << endl;}cout << "Completed" << endl;return 0;}
GUI
然后,我尝试编译 Qt5,事实上尝试了几次,但每次都遇到不同的错误。我发现的第一个错误之一是 Qt 正在将各种文件安装到我的 IVI 的挂载系统根镜像中,但默认情况下,该镜像没有足够的空间来容纳它们。我使用以下命令使用 dd 命令将 system.img 的大小增加了 1GB,然后使用 resize2fs 调整 system.img 中的文件系统大小,以便能够使用新增的空间:
dd if=/dev/zero count=4 bs=256M >> system.imgsudo mount system.img system_imageFULL_SYSROOT_DIR=$(realpath system_image)SYSROOT_MOUNT_DEVICE=$(df | grep $FULL_SYSROOT_DIR | awk '{print $1}')sudo resize2fs $SYSROOT_MOUNT_DEVICEcp system_image/usr/lib/libGLESv2.so.2 system_image/usr/lib/libGLESv2.so./configure -device arm-generic-g++ -device-option CROSS_COMPILE=/home/greenluigi1/QtDev/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi- -opensource -confirm-license -sysroot /home/greenluigi1/QtDev/system_image -skip declarative -nomake examples -skip virtualkeyboard 该脚本将下载并安装正确的交叉编译器、QtCreator,并编译正确版本的 Qt。由于系统镜像的挂载是临时的,我还包含了挂载脚本,以便在重新启动前和开发前重新挂载系统镜像。
现在,我就快完成了,我只需要设置 QtCreator 来使用我的设置即可。
我浏览了系统中的所有 GUI 应用程序,并寻找最小的一个。我选择了位于 /usr/share/AMOS/EProfilerApp 中的 EProfilerApp。根据名称,它是一个简单的 GUI 应用程序,用于查看/管理 AMOS,即内置的系统性能分析工具。我将 EProfilerApp 导入到 IDA 中,并开始分析其二进制代码:
每个 Helix 应用程序的 main() 函数看起来像这样:
int main(int argc, char *argv[]){QApplication app(argc, argv);MyApplication myApplication = MyApplication();myApplication.init(app, argc, argv);return app.exec();}
1. 应用视图(App Views)
- 表示一个用户可以与之交互的 Qt5 屏幕/窗口。这包括全屏窗口以及弹出窗口。
- 负责创建、显示、隐藏和销毁普通的 Qt5 窗口。
2. 应用服务(App Services)
- 表示一个后台进程。
3. 事件接收器(Event Receivers)
- 表示用于处理系统中可能发出的各种事件的处理程序。
该应用程序具有一个名为“ExampleGuiAppView”的单个 AppView,其组件名称为“com.greenluigi1.guiExample.TestAppView”。这个 AppView 创建了一个简单的窗口,其中包含 4 个按钮:
锁定车辆所有的门。
Unlock
解锁车辆的门。
表现得像钥匙的解锁一样。按下一次将解锁驾驶员侧门,按下两次将解锁所有门。
Test
向 Logcat 日志打印一条测试消息。
Exit
使用 finish() 函数退出应用程序。
但在此之前,还有一些事情需要做。我们需要“注册”该应用程序,以便 Helix 能够识别它。Helix 的应用程序管理器通过读取 /etc/appmanager/appconf 目录中的 .ini 文件来工作。每个 .ini 文件告诉 Helix 应用程序的组件名称,列出每个 AppView、AppService 和 EventReceiver,并指定您的 EventReceivers 监听的事件。
一个典型的应用程序配置看起来像这样:
[Application]Name=com.company.grouping.appNameExec=/usr/share/app-appName-1.0.0/appName[TestAppService]#ComponentName : com.company.grouping.appName.TestAppServiceType=AppService[TestAppView]#ComponentName : com.company.grouping.appName.TestAppViewType=AppView[TestEventReceiver]#ComponentName : com.company.grouping.appName.TestEventReceiverType=EventReceiverEvent=com.mobis.caudio.ACTION.POWER_OFF
在“[Application]”组之后,可以跟随任意数量的组。每个组代表一个新的组件。组的名称指示组件的名称,例如“[TestAppView]”表示它正在定义一个名为“TestAppView”的组件,或者在这种情况下更具体地说是:“com.company.grouping.appName.TestAppView”。在组件组下是该组件的特定设置。每个组件组都有一个类型,可以是 AppView、AppService 或 EventReceiver。每种类型的组件都可以有自己的设置,例如 EventReceiver 类型具有 Event 属性,该属性是 Receiver 订阅的事件的逗号分隔列表。以“#”开头的行是注释,被 Helix 忽略。
我只需要制作自己的 .appconf 文件,以便启动我的应用程序。这是我想到的内容:
[Application]Name=com.greenluigi1.guiExampleExec=/appdata/guiExample[TestAppView]# ComponentName : com.greenluigi1.guiExample.TestAppViewType=AppView
我将已编译的应用程序及其配置文件复制到了我的 USB 驱动器上,并启动了我的反向 shell。我将根目录挂载为读/写,以便可以修改配置文件夹。然后,我将我的 GuiExampleApp.appconf 配置文件复制到 /etc/appManager/appconf/ 文件夹,并将应用程序本身复制到 /appdata/ 文件夹。
然后我发送了重启命令,等待 IVI 重新启动。
现在我只需要启动我的应用程序,但我应该如何做呢?从命令行运行应用程序时,它不会自行执行任何操作。我们需要告诉 Helix 来启动它。
幸运的是,在之前的调查中,我发现了一个已经安装在机器上的命令行工具,可以做到这一点:appctl。appctl 是一个小程序,允许您:
appctl startAppView com.greenluigi1.guiExample.TestAppView推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……




还没有评论,来说两句吧...