Windows Mobile 6.x Hackery Explained
Posted by Chainfire on 23-05-2012 at 13:35:00 - Comments: 115 - Views: 31445
Tags: Marketplace Good news Developer tools Windows Mobile
Tags: Marketplace Good news Developer tools Windows Mobile
This week, the Windows Mobile 6.x Marketplace was closed. The end of an era :)
While most current readers will probably know me from my work with Android, I used to do a lot of things on Windows Mobile. Several of those projects were pretty unique, due to hacking techniques employed that few others knew. I am referring here to runtime/dynamically patching kernel code, coredll imports, etc.
Some of these projects include FPU Enabler (which replaced the standard floating point functions on the last few WM phones with FPU based variants - together with NuShrike), AutoClosePatch (improve multitasking behavior on low memory devices like the Samsung Omnia II), Marketplace Region Switch (switched your region in Marketplace, before Microsoft built in that option, by faking MCC data), and many more.
Of course, let us not forget Marketplace Advanced Protection Patch. Some people thought I didn't actually have this due to me not releasing it. At the time I thought it more important to protect other developers. As Marketplace is now shutdown however, I've decided to release the code.
Its a nice trip down memory lane, and I will take some time to somewhat explain some of the techniques I have used. I will do my best, but it has been three years since I have written this code, so not everything I write may be 100% correct. I will try to keep it short-ish, but I know the article will still be long - I could write entire books on this subject :)
You will need the accompanying code, which is hosted at GitHub.
The test project
Let us start with the Test_VS2K8 folder. This folder contains the Visual Studio test project. It is simply the minimal code to test Marketplace's "Advanced" Protection. Aside from _tmain function, the entirety of the MPAdvTest.cpp file is copy/pasted from Microsoft's example code.
From a code breaker's perspective, what we are looking for is a way to get the VerifyLicense function return TRUE. On Windows Mobile specifically, the easiest way to make this happen for all programs with a single patch is modifying return values of functions exposed by coredll.dll.
If you look closely at the code, you will notice that the VerifyLicense function will return TRUE if both:
- The HKCU\Security\Software\Microsoft\Marketplace\Licenses\<licensecode> registry key can be read and is of type REG_BINARY
- The CryptVerifySignature returns TRUE
We can achieve these conditions by:
- Making sure HKCU\Security\Software\Microsoft\Marketplace\Licenses exists
- Patching the RegQueryValueExW function
- Patching the CryptVerifySignatureW function
Both of these functions are exposed through coredll.dll, so let's get busy!
The patch project
The patch code is in the Patch_FPC folder. This folder contains the FreePascal test project. Yes, it's written in Pascal, get over it. It's also fairly visible I wrote it in a rush, the main unit is still called unit1 !
It's difficult to compile due to depending on KOL-CE for the UI, which at least at the time I wrote this patch had several versions that could conflict. It should be fairly easy to turn into a console project without that dependency, though.
It is unlikely you will be trying to compile this anyway, so let's just get down to the explaining.
The important background code employed for the hacking is located in the upatch.pas file. Various versions of this unit are used in several of my WM hacking projects. The code looks simple enough, but make no mistake, lots and lots of hours were lost by several hackers to get all this information together. Remember, it's not like we had Windows Mobile source code :)
You can mostly the ignore uregistry.pas, it contains utility functions only.
The main code can be found in unit1.pas.
Let's walk through the actual patch code, located in unit1.pas, starting at line 134:
These two lines do something very important: we switch to kernel mode and enable read/write access to all processes, threads, and memory range. Essentially we're disabling all those nasty protections designed to prevent exactly what we are trying to do.
Skipping over the registry key creation bit, we go on at lines 143-144:
What we are doing here is filling an array with the raw bytes that are the compiled code of our replacement functions, defined on lines 61-96:
(Note: opPatch is simply a variable containing the raw binary for the "return" instruction, which should be used as end marker for copying the function - this is not always exactly the same for each function! We also know that the function will not be longer than 1024 bytes)
While most current readers will probably know me from my work with Android, I used to do a lot of things on Windows Mobile. Several of those projects were pretty unique, due to hacking techniques employed that few others knew. I am referring here to runtime/dynamically patching kernel code, coredll imports, etc.
Some of these projects include FPU Enabler (which replaced the standard floating point functions on the last few WM phones with FPU based variants - together with NuShrike), AutoClosePatch (improve multitasking behavior on low memory devices like the Samsung Omnia II), Marketplace Region Switch (switched your region in Marketplace, before Microsoft built in that option, by faking MCC data), and many more.
Of course, let us not forget Marketplace Advanced Protection Patch. Some people thought I didn't actually have this due to me not releasing it. At the time I thought it more important to protect other developers. As Marketplace is now shutdown however, I've decided to release the code.
Its a nice trip down memory lane, and I will take some time to somewhat explain some of the techniques I have used. I will do my best, but it has been three years since I have written this code, so not everything I write may be 100% correct. I will try to keep it short-ish, but I know the article will still be long - I could write entire books on this subject :)
You will need the accompanying code, which is hosted at GitHub.
The test project
Let us start with the Test_VS2K8 folder. This folder contains the Visual Studio test project. It is simply the minimal code to test Marketplace's "Advanced" Protection. Aside from _tmain function, the entirety of the MPAdvTest.cpp file is copy/pasted from Microsoft's example code.
From a code breaker's perspective, what we are looking for is a way to get the VerifyLicense function return TRUE. On Windows Mobile specifically, the easiest way to make this happen for all programs with a single patch is modifying return values of functions exposed by coredll.dll.
If you look closely at the code, you will notice that the VerifyLicense function will return TRUE if both:
- The HKCU\Security\Software\Microsoft\Marketplace\Licenses\<licensecode> registry key can be read and is of type REG_BINARY
- The CryptVerifySignature returns TRUE
We can achieve these conditions by:
- Making sure HKCU\Security\Software\Microsoft\Marketplace\Licenses exists
- Patching the RegQueryValueExW function
- Patching the CryptVerifySignatureW function
Both of these functions are exposed through coredll.dll, so let's get busy!
The patch project
The patch code is in the Patch_FPC folder. This folder contains the FreePascal test project. Yes, it's written in Pascal, get over it. It's also fairly visible I wrote it in a rush, the main unit is still called unit1 !
It's difficult to compile due to depending on KOL-CE for the UI, which at least at the time I wrote this patch had several versions that could conflict. It should be fairly easy to turn into a console project without that dependency, though.
It is unlikely you will be trying to compile this anyway, so let's just get down to the explaining.
The important background code employed for the hacking is located in the upatch.pas file. Various versions of this unit are used in several of my WM hacking projects. The code looks simple enough, but make no mistake, lots and lots of hours were lost by several hackers to get all this information together. Remember, it's not like we had Windows Mobile source code :)
You can mostly the ignore uregistry.pas, it contains utility functions only.
The main code can be found in unit1.pas.
Let's walk through the actual patch code, located in unit1.pas, starting at line 134:
Code
#
1
SetKMode(TRUE);
2
SetProcPermissions($FFFFFFFF);
These two lines do something very important: we switch to kernel mode and enable read/write access to all processes, threads, and memory range. Essentially we're disabling all those nasty protections designed to prevent exactly what we are trying to do.
Skipping over the registry key creation bit, we go on at lines 143-144:
Code
#
1
fNewCryptVerifySignature := GetFunctionCode(@newCryptVerifySignatureW, 1024, opPatch);
2
fNewRegQueryValueEx := GetFunctionCode(@newRegQueryValueExW, 1024, opPatch);
What we are doing here is filling an array with the raw bytes that are the compiled code of our replacement functions, defined on lines 61-96:
(Note: opPatch is simply a variable containing the raw binary for the "return" instruction, which should be used as end marker for copying the function - this is not always exactly the same for each function! We also know that the function will not be longer than 1024 bytes)
Code
#
1
function newCryptVerifySignatureW(hHash: DWORD; pbSignature: PBYTE; dwSigLen: DWORD; hPubKey: DWORD; sDescription: PWideChar; dwFlags: DWORD): BOOL;
2
begin
3
Result := True;
4
end;
5
6
function newRegQueryValueExW(hKey:HKEY; lpValueName:LPCWSTR; lpReserved:LPDWORD; lpType:LPDWORD; lpData:pointer;lpcbData:LPDWORD):LONG;
7
var
8
c: Byte;
9
p: PBYTE;
10
oldRQVE: TRegQueryValueExW;
11
begin
12
oldRQVE := TRegQueryValueExW($12345678);
13
14
Result := 6; // ERROR_INVALID_HANDLE
15
16
if lpValueName <> nil then begin
17
DWORD(p) := DWORD(lpValueName);
18
19
c := 0;
20
&