Skip to content

Commit 4f303e0

Browse files
committed
add more content for reversing turbo
1 parent 06a88ac commit 4f303e0

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed
154 KB
Loading
56 KB
Loading

content/post/reversing-nitro/index.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,79 @@ Initially, I tried to do some trial and error using a tool I discovered called [
3434
I also made a small documentation [patch](https://web.git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/diff/Documentation/wmi/driver-development-guide.rst?id=98e45f0d7b99ceac029913ce3a161154a8c4c4a7) during this time to mention this tool in the WMI driver development [guide](https://docs.kernel.org/wmi/driver-development-guide.html).
3535

3636
## Reversing the NitroSense app
37-
Thus it began, my first foray into reverse engineering a real app. The NitroSense app was written in C# and thus I used dotPeek to decompile it. From there, I found the function which was responsible for setting the fan speeds after searching around for a bit:
37+
Thus it began, my first foray into reverse engineering a real app. The NitroSense app was written in C# and thus I used dotPeek to decompile it.
38+
### Fan Speeds Cracked
39+
While searching for the input values for the overclock WMI call, I chanced upon a function that was responsible for setting the fan speeds -
40+
```C
41+
public static bool set_all_fan_mode(CommonFunction.Fan_Mode_Type mode_index)
42+
{
43+
ulong intput = 9;
44+
switch (mode_index)
45+
{
46+
case CommonFunction.Fan_Mode_Type.Auto:
47+
intput |= 4259840UL;
48+
break;
49+
case CommonFunction.Fan_Mode_Type.Max:
50+
intput |= 8519680UL;
51+
break;
52+
case CommonFunction.Fan_Mode_Type.Custom:
53+
intput |= 12779520UL;
54+
break;
55+
}
56+
return ((int) WMIFunction.SetAcerGamingFanGroupBehavior(intput).GetAwaiter().GetResult() & (int) byte.MaxValue) == 0;
57+
}
58+
```
3859
60+
As we can see, input values of the WMI function are readily available here! There are three magic values which correspond to the three different fan modes. Was a bit surprised to the see the typo in the 'intput' variable though, kind of refreshing to know that even billion dollar companies have such mistakes in their code lol.
61+
62+
### In Search Of Overclocks..
63+
The overclock function was sadly not as simple of an egg to crack. I traced through the GUI code for the app and narrowed it down to this particular function -
64+
```C
65+
public static async Task<int> set_operation_mode(int Operation_Mode)
66+
{
67+
int output = -1;
68+
try
69+
{
70+
NamedPipeClientStream cline_stream = new NamedPipeClientStream(".", "PredatorSense_service_namedpipe", PipeDirection.InOut);
71+
cline_stream.Connect();
72+
output = await Task.Run<int>((Func<int>) (() =>
73+
{
74+
IPCMethods.SendCommandByNamedPipe(cline_stream, 30, (object) (uint) Operation_Mode);
75+
cline_stream.WaitForPipeDrain();
76+
byte[] buffer = new byte[9];
77+
cline_stream.Read(buffer, 0, buffer.Length);
78+
return BitConverter.ToInt32(buffer, 5);
79+
})).ConfigureAwait(false);
80+
cline_stream.Close();
81+
return output;
82+
}
83+
catch (Exception ex)
84+
{
85+
return output;
86+
}
87+
}
88+
```
89+
Don't worry if it all looks like gibberish to you, it did to me as well when I first came across it. Since i was wholly unfamiliar with the Windows API, I took to ChatGPT to explain the code to me like a 5 year old. GPT explained that this function was creating something called a ["Named Pipe"](https://en.wikipedia.org/wiki/Named_pipe) which is used for inter-process communication.
90+
91+
Uh oh, this meant that the actual WMI call was was being made by a process on the receiving end of this pipe. Interestingly, I noted that the name of the pipe was 'PredatorSense_**service**', suggesting that the recipient process was a service.
92+
93+
While we are here, let me also comment that the `Operation_Mode` argument of `set_operation_mode()` took one of three values: 0, 1 or 4. Which makes sense considering that my lapop has three performance modes.
94+
95+
### The Final Gatekeeper
96+
Sure enough, there was indeed a service in services.msc named `Predator Service`, the service started a process called `Pssvc.exe`. This particular program was written in C++, I initially used IDA to dissassemble it before remembering that I had pretty much 0 knowledge of assembly ;-;
97+
98+
That's when I remembered Ghidra, a reversing tool developed by the NSA, that I had used during my first CTF contest - inCTFj. Ghidra tries its best to produce a readable C-like program from the disassembled code.
99+
100+
After some heavy decompiling on the service file using Ghidra I finally found out that the value is read from the named pipe and then used to call a function from a function pointer table as follows:
101+
```C
102+
(*(code *)(&PTR_LAB_140052c90)[uVar14])(puVar5,puVar8,&local_250,&local_244);
103+
```
104+
Here, `&PTR_LAB_140052c90` refers to the following function pointer table:
105+
106+
<img src="function_table.png" width="480">
107+
108+
If you remember from [earlier](#in-search-of-overclocks), a command index of 30 was passed into the named pipe along with the Operation Mode and this corresponds to the function pointer that I've highlighted in the image. Here is the relevant section of the code which calls this particular function:
109+
110+
<img src="ghidra_decomp.png" width="480">
111+
112+
Yes it is one hell of a monstrosity, but after staring at it for a long time, I figured out that all it does is pass an array of bytes taken from the named pipe and their corresponding byte offsets to the function. You can observe this in the last highlighted line of code, `puVar5` is the array of bytes and `puVar8` are the byte offsets (I think anyways)

0 commit comments

Comments
 (0)