Global Subclassing - Windows Mobile Development and Hacking General

OK, I know that global subclassing of windows is formally not supported. However, I have a few ideas of how to do it. First, I was wondering if anyone knows whether or not the internal window structure is similar to the internal structure used on Windows NT.
Also, I was wondering if anyone knows how to locate the internal window table. I figure that it's contained somewhere in GWES as it contains the USER functions. I've been researching CreateWindowEx, but I haven't been able to land on anything specific.
Thanks!

Here is info that I've digged in last 10 minutes. It can be incorrect.
chmckay said:
First, I was wondering if anyone knows whether or not the internal window structure is similar to the internal structure used on Windows NT.
Click to expand...
Click to collapse
It is completely different.
As far as I've seen from coredll decompilation the HWND is internally translated to internal CWindow class by an internal "static CWindow* CWindow::coredllPwndFromHwnd(HWND__*)" function defined in twinuser.obj file in thunks.lib in PlatformBuilder. I've dumped it from a COREDLL.PDB file from old PlatformBuilder 4.0beta. Here is it, cleaned from unnecessary function prototypes:
Code:
struct CWindow
{
struct CWindow* m_pcwndNext;
struct CWindow* m_pcwndParent;
struct CWindow* m_pcwndChild;
unsigned m_sig;
struct CWindow* m_pcwndOwner;
struct CWindow* m_pcwndOwned;
struct CWindow* m_pcwndNextOwned;
struct CWindow* m_pcwndRestore;
struct tagRECT m_rc;
struct tagRECT m_rcClient;
void* m_pgdiwnd;
void* m_pgdiwndClient;
void* m_pgdiwndClientUpdate;
struct tagRECT m_rcRestore;
struct _GENTBL* m_ptblProperties;
unsigned m_dwState;
struct ScrollBarInfoInternal* m_psbii;
DWORD* m_pszName;
struct MsgQueue* m_pmsgq;
DWORD m_himc;
unsigned m_grfStyle;
unsigned m_grfExStyle;
struct CWindowClass* m_pwc;
long m_lID;
long m_lUserData;
void* m_hprcCreator;
void* m_hthdCreator;
void* m_hprcWndProc;
int (*m_pfnWndProc)(HWND__*, DWORD, DWORD, int);
struct HRGN__* m_hrgnWindowRgn;
struct HRGN__* m_hrgnVisible;
struct HRGN__* m_hrgnUpdate;
struct HRGN__* m_hrgnClientVisible;
struct HRGN__* m_hrgnClientUpdate;
struct HMENU__* m_hmenu;
void* m_hprcDestroyer;
struct CWindow::__unnamed::__unnamed m;
unsigned m_grfBitFields;
DWORD m_rgdwExtraBytes[0];
};
The structure may have been changed in the current version of OS.
The code of coredllPwndFromHwnd() function taken from iMate 1.72 ROM:
Code:
.text:01F6E65C sub_1F6E65C ; COD
.text:01F6E65C ; sub
.text:01F6E65C 10 40 2D E9 STMFD SP!, {R4,LR}
.text:01F6E660 FE 24 C0 E3 BIC R2, R0, #0xFE000000
.text:01F6E664 2C 00 9F E5 LDR R0, =unk_1FC65AC ; this is a "g_dwGwesBase" variable
.text:01F6E668 00 10 90 E5 LDR R1, [R0]
.text:01F6E66C 01 40 82 E0 ADD R4, R2, R1
.text:01F6E670 1C 10 9F E5 LDR R1, =0x574E4457 ; Magic value? It is in m_sig member.
.text:01F6E674 0C 00 94 E5 LDR R0, [R4,#0xC]
.text:01F6E678 01 00 50 E1 CMP R0, R1
.text:01F6E67C 57 0E A0 13 MOVNE R0, #0x570
.text:01F6E680 08 00 80 13 ORRNE R0, R0, #8
.text:01F6E684 00 40 A0 13 MOVNE R4, #0
.text:01F6E688 72 0C 00 1B BLNE SetLastError
.text:01F6E68C 04 00 A0 E1 MOV R0, R4
.text:01F6E690 10 80 BD E8 LDMFD SP!, {R4,PC}
I can upload somewhere the complete dump of all structures from coredll, gwes, nk. But they are taken form old PlatformBuilder, because latest version has this data removed from PDB files.
I don't know the address that containf the head of this linked list, but probably it starts from the desktop window. So you can get CWindow of desktop and enumerate windows with m_pcwndNext/m_pcwndChild members.
The other problem is that we cannot determine the g_dwGwesBase value that is added to HWND to determine CWindow pointer.
One idea. You can try "GetWindowLong" to get data from CWindow structure. But its predefined offsets look very strange.

Mamaich,
Thank you VERY much. That was just the information I needed! I've managed to locate the class information and successfully subclass a window globally on the emulator (my cradle is at home, so I can't test this on my device).
Here's what I've learned that you might be interested in:
the g_dwGwesBase variable is actually a pointer to the virtual memory location of gwes.exe. Also, the 0xfe000000 value is specific to the processor. In this case, the value is (hwnd & ~0xfe000000), while on the x86/emulator platform, it is (hwnd & 0x1fffffff). I don't have access to the MIPS or SH3 libraries (as I don't have a full copy of Platform Builder).
Anyway, this is what the coredllPwndFromHwnd() function amounts to:
DWORD *wnd = (hwnd & ~0xfe000000) + g_dwGwesBase;
if( wnd[3] == 0x574e4457 )
return wnd;
else {
SetLastError(0x578);
return NULL;
}
The 0x574e4457 is not processor specific (as it appears in the x86 libs). Also, you easily replace the "+ g_dwGwesBase" with this:
DWORD *wnd = (DWORD*)MapPtrToProcess((LPVOID)(hwnd & ~0xfe000000), hHandleToGWES);
Thank you again for your help. Now, the only thing I have left to do is get the magic numbers for MIPS and SH3 and I'll be all set.

chmckay said:
The 0x574e4457 is not processor specific (as it appears in the x86 libs).
Click to expand...
Click to collapse
0x574e4457 == 'WNDW', so it would be the same for all platforms. I also don't have MIPS/SH3 libraries for platformBuilder.
The value ~0xfe000000 == 0x1fffffff, so it should also be the same an all platforms (it looks similar to HANDLE_ADDRESS_MASK, which is also same for all, the only difference is that HANDLE_ADDRESS_MASK clears the lowest 2 bits of address).

I can't believe that I didn't catch that the values were the same . Anyway, I looked up HANDLE_ADDRESS_MASK and I'm a little concerned that it doesn't appear in ksshx.h. I guess that begs the question as to whether or not it is used on that platform. I'll do some investigating and see what I can find.
As far as the lower two bits are concerned, it's probably not a big deal. Using Spy++ on the emulator shows that EVERY window handle has the least significant byte set to 0. So, maybe the HANDLE_ADDRESS_MASK is the ticket.
Thank you again for your help. I've managed to do what I need to do. I wouldn't have been able to get this far without you. Thanks!

Apparently there is one more thing that I need in order to have my project working perfectly. In Gwes, there is a structure that contains some data that I need to manipulate in order to achieve some consistency. Unfortunately this structure is contained in a global variable that is not exposed to any outsider.
What I'm wondering is this: if I have a dll injected into the Gwes process, is there a way that I could locate the address of that global variable on various devices? I guess what I'm looking for is more of a technique than anything else. If this were a desktop binary, I would just access a specific location, but since the OS is apparently recompiled for different devices, that's not feasible as the location changes based upon different variables.
So, if anyone can help me out, I'd appreciate it. Thanks again!

chmckay said:
What I'm wondering is this: if I have a dll injected into the Gwes process, is there a way that I could locate the address of that global variable on various devices?
Click to expand...
Click to collapse
Typically you should search for such address using signatures of code that accesses it. It is easier to explain by an example.
For example you may determine the value of g_dwGwesBase by searching for the code that accesses it. Look at the coredllPwndFromHwnd function. At its end it has an off_1F6E698 variable that contains the address of g_dwGwesBase. This is a function code:
Code:
coredllPwndFromHwnd:
10 40 2D E9 STMFD SP!, {R4,LR}
FE 24 C0 E3 BIC R2, R0, #0xFE000000
2C 00 9F E5 LDR R0, =g_dwGwesBase
00 10 90 E5 LDR R1, [R0]
... skipped ...
72 0C 00 1B BLNE SetLastError
04 00 A0 E1 MOV R0, R4
10 80 BD E8 LDMFD SP!, {R4,PC}
; End of function coredllPwndFromHwnd
57 44 4E 57 aWdnw DCB "WDNW"
AC 65 FC 01 off_1F6E698 DCD g_dwGwesBase
You see that the needed address is located after the end of this function after the "WDNW" constant. "WDNW" {57 44 4E 57} is located in lots of places in coredll, but only in one place it is prefixed by "LDMFD SP!, {R4,PC}" (10 80 BD E8) command . So you may search for bytes {10 80 BD E8 57 44 4E 57} and the next DWORD after them would contain the address of g_dwGwesBase.
This function is the same in different OSes on different devices, so this method would work on every PocketPC with ARM CPU.
You should carefully select the signatures. In your program you should keep a set of signatures for most common versions of ROMs, for different CPUs, etc.
To search for a giver pattern you may use this function:
Code:
#define _XX_ '?'
int RabSearch(unsigned char *SearchString, int StringLen,
unsigned char *SearchBuff, int BuffSize)
{
register int i,j;
if (BuffSize < StringLen) return -1;
for(i=0;i<(BuffSize-StringLen);i++)
{
for(j=0;j<StringLen;j++)
{
if (
(SearchString[j] != _XX_) &&
(SearchString[j] != SearchBuff[i+j])
)
break;
}
if (j==StringLen) return i;
}
return -100;
}
This code is taken from [email protected].
You may place "?" char in a buffer to indicate that this byte should be ignored on search.
This method is commonly used by crackers to create "universal" cracks that work with different versions of a given program

Related

help for SIM Acces

Hi all,
I am new to this forum and happy to be part of it. I am facing one problem. Hope you all can take a look at this.
I have an EAP-SIM application which needs to be ported to Windows CE Pocket PC 2003. It will probably run on HP iPAQ. I need to get the IMSI of the SIM card and run the GSM (A3/A5/A8) algorithms through my application.
After a lot of research, i found it might be possible through AT commands and with the help of RIL(Radio Interface Layer). I tried some samples, but is not working properly. I saw some AT commands in this link
http://ftp.rz.tu-bs.de/pub/mirror/cc..._log_commented
Next I tried this with RIL.
I need to know how i can get IMSI and send some PDU to the SIM card to run the algorithm. Is it possible ? through RIL ? AT command ? . Your valuable help or suggestion is expected.
-------------------------------------------------------------------
const BYTE SELECT_FILE_CMD[] = {(BYTE)0xA0, (BYTE)0xA4, (BYTE)0x00, (BYTE)0x00, (BYTE)0x02,(BYTE)0x3F,(BYTE)0x00};
const BYTE GSM_DIR_CMD[] = {(BYTE)0xA0, (BYTE)0xA4, (BYTE)0x00, (BYTE)0x00, (BYTE)0x02,(BYTE)0x7F,(BYTE)0x20};
const BYTE SELECT_EF_IMSI_CMD[] = {(BYTE)0xA0, (BYTE)0xA4, (BYTE)0x00, (BYTE)0x00, (BYTE)0x02,(BYTE)0x6F,(BYTE)0x07};
const BYTE GET_IMSI_CMD[] = {(BYTE)0xA0,(BYTE)0xB0,(BYTE)0x00,(BYTE)0x00, (BYTE)0x09 };
const BYTE READ_IMSI_CMD[] = {(BYTE)0xA0,(BYTE)0xC0,(BYTE)0x00,(BYTE)0x00, (BYTE)0x09 };
result = RIL_Initialize(1, ResultCallback, NotifyCallback, dwNotificationClasses, g_dwParam, &g_hRil);
res_UserIdentity = RIL_GetUserIdentity(g_hRil);
//res_SelectFile = RIL_SendSimCmd(g_hRil, SELECT_FILE_CMD,sizeof(SELECT_FILE_CMD));
//res_Select_IMSI = RIL_SendSimCmd(g_hRil, SELECT_EF_IMSI_CMD,sizeof(SELECT_EF_IMSI_CMD));
//res_Get_IMSI = RIL_SendSimCmd(g_hRil, GET_IMSI_CMD,sizeof(GET_IMSI_CMD));
//res_Read_IMSI = RIL_SendSimCmd(g_hRil, READ_IMSI_CMD,sizeof(READ_IMSI_CMD));
-------------------------------------------------------
Thanks,
Hi, could you repost the link you added, its not working when I click on it.
The commands to select the IMSI seem correct, you have the address right, although I think you might have the last 2 in the wrong order. The 0xb0 command is read binary, and 0xc0 is get response. Typically you would select 3f00, 7f20, 6f07, then send the response command with the length as the final byte (given as the second returned byte from the previous command). You then use the read binary command with the length as the final byte.
Having said that, as you already know the length, you could skip the response command altogether.
here is the trace from my PC based program im developing when selecting the IMSI:
A0 A4 00 00 02 3F 00
A0 A4 00 00 02 7F 20
A0 A4 00 00 02 6F 07
9F 0F
A0 C0 00 00 0F
90 00 00 00 00 09 6F 07 04 00 1D 00 1D 01 02 00 00
A0 B0 00 00 09
IMSI: 90 00 ......
Hi,
Thanks for your reply. Please find the link below
http://ftp.rz.tu-bs.de/pub/mirror/ccc_Chaos_Computer_Club/ftp.ccc.de/gsm/gsm_log_commented
The real problem is am using RIL. In RIL_SenSimCmd ( ), the error code i got is
80004001 which means its not implemented. I am using HP iPAQ. Does this execution of AT commands depends upon the mobile phone ? As you mentioned about your PC program,Are you using smart card reader or something else ? Can you please tell me how you did it ?
Right now am just trying to send a single AT command to select the GSM file after RIL initialization. That itself is failing.
const BYTE GSM_DIR_CMD[] = {(BYTE)0xA0, (BYTE)0xA4, (BYTE)0x00, (BYTE)0x00, (BYTE)0x02 ,(BYTE)0x7F,(BYTE)0x20};
result = RIL_Initialize(1, ResultCallback, NotifyCallback, dwNotificationClasses, g_dwParam, &g_hRil);
if (result < 0)
{
wsprintf(szString,L"RIL_Init-%d",result);
ShowMessage(szString);
}
res_GSMDir = RIL_SendSimCmd(g_hRil, GSM_DIR_CMD,sizeof(GSM_DIR_CMD));
if (res_GSMDir < 0)
{
wsprintf(szString,L"res_GSMDir %x",res_GSMDir);
ShowMessage(szString);
print_error(-1 * res_GSMDir);
}
So I assume my iPAQ is not allowing me to execute commands ?. Please give a brief about this. Please let me know if you didnt get the link. I wil send it to your mail id..
Thanks,
My knowledge with AT commands and RIL is limited im afraid, but I'd guess ipaq's dont use the standard AT commands. The error being returned would suggest to me that the command is incorrect and not recognised, so you're probably sending it in the wrong format.
All I can do is point you to a few links you probably have already looked at, namely microsofts msdn article on RIL application
http://msdn2.microsoft.com/en-us/library/ms894929.aspx
and handhelds site, which may contain useful info on your device that could help in development.
http://handhelds.org/
As for my program, im writting it in VC++ using the scard platform. And yes, im using a card reader.
The command structure is:
CCardServer::SCardCommand(LPCSTR Cmd, LPSTR DataIn, INT DataInLen, LPSTR DataOut, INT DataOutLen)
Hi sanal,
sanal said:
... I have an EAP-SIM application which needs to be ported to Windows CE Pocket PC 2003.
Click to expand...
Click to collapse
EAP-SIM --> i wish you good luck
sanal said:
... I need to get the IMSI of the SIM card and run the GSM (A3/A5/A8) algorithms through my application.
After a lot of research, i found it might be possible through AT commands and with the help of RIL(Radio Interface Layer). I tried some samples, but is not working properly. I saw some AT commands in this link
Click to expand...
Click to collapse
why not using SIM Manager? see SIM Manager Reference at MSDN.
This API is available for PocketPC 2002 and later..
Here a codesnippet out of SIMSpider, which i've written some time ago..
(if SIM Manager fails, then it's probably not implemented by hp for your device..)
Code:
// dwAddress:
// 0x6F07: IMSI
// 0x6F20: KC Ciphering Key
void ReadSIM ( DWORD dwAddress )
{
HSIM hSim;
HRESULT hr = SimInitialize ( 0, NULL, NULL, &hSim );
if ( hr == S_OK )
{
SIMRECORDINFO sri;
memset ( &sri, 0, sizeof(sri) );
sri.cbSize = sizeof(sri);
hr = SimGetRecordInfo ( hSim, dwAddress, &sri );
if ( hr == S_OK )
{
DWORD dwBytesRead;
BYTE pBuf [ 4096 ];
hr = SimReadRecord ( hSim, dwAddress, sri.dwRecordType, NULL, (LPBYTE)pBuf, sizeof(pBuf), &dwBytesRead );
if ( hr == S_OK )
{
// here you can decode the data according to gsm-spec
// e.g. http://www.ttfn.net/techno/smartcards/gsm11-11.pdf
}
else
wprintf ( L"Failed to read Record!" );
}
hr = SimDeinitialize ( hSim );
}
else
wprintf ( L"SimInitialize failed with %08X", hr );
}
for EAP-SIM you may need the ciphering key too.. don't know for sure..
for decoding the sim-files you can find any needed info e.g. in http://www.ttfn.net/techno/smartcards/gsm11-11.pdf
and so on...
hope it helps
Cheers,
ikarus
Hi ikarus,
Thanks a lot for your reply. I am reached half way. Got IMSI and Kc with SIM Manager. What to do with the Run GSM Algorithms. I think for that we need to send some commands to SIM. I have no hope of doing algorithms execution through SIM manager. Any idea ?
Hello sanal,
you're right. With SIM Manager there seems to be no way for running gsm algorithms.
Furthermore i'm not sure if you really need the imsi and kc.
As far as i know for eap-sim you send the algorithm (sim) a random, which the nas (respectively the authentication-entity behind) sends to you.
I'm not very well experienced with this, so you're on your own.
hm.. you could have a look at RIL_SendRestrictedSimCmd, but there is no constant for "Run GSM Algorithm".
You could also try RIL_SendSimCmd and format the command according to gsm-specs. In the mentioned document there is a chapter 9 - Description of the commands ..
(but i guess an official gsm-spec would be more helpful)
Maybe another user can help more?
good luck !
ikarus
yes I think needs to do more research. Particularly whether iPAQ supports this AT commands. Bcoz as of i know phones restrict this command AT+CSIM. As you mentioned i have already checked the specs ,
as limbmaster said i need to check whether am sending the commands correct or wrong. But my doubt is when i try AT+CSIM through serial com, it says error. then This is bcoz phone is not allowing you. Then how RIL will work.. Anyway need to look how GSM algorithm can be done.

http://www.canyoucrackit.co.uk/

http://www.canyoucrackit.co.uk/
Not Evo related, but still fun. It's stage 1 of a challenge, that is said to be a GCHQ Recruitment Test.
I don't know why this is under the HTC Supersonic but here is the hex data, so you don't have to manually type it in yourself:
Code:
eb 04 af c2 bf a3 81 ec 00 01 00 00 31 c9 88 0c
0c fe c1 75 f9 31 c0 ba ef be ad de 02 04 0c 00
d0 c1 ca 08 8a 1c 0c 8a 3c 04 88 1c 04 88 3c 0c
fe c1 75 e8 e9 5c 00 00 00 89 e3 81 c3 04 00 00
00 5c 58 3d 41 41 41 41 75 43 58 3d 42 42 42 42
75 3b 5a 89 d1 89 e6 89 df 29 cf f3 a4 89 de 89
d1 89 df 29 cf 31 c0 31 db 31 d2 fe c0 02 1c 06
8a 14 06 8a 34 1e 88 34 06 88 14 1e 00 f2 30 f6
8a 1c 16 8a 17 30 da 88 17 47 49 75 de 31 db 89
d8 fe c0 cd 80 90 90 e8 9d ff ff ff 41 41 41 41
(I'll edit this post if you find any transcription errors)
Suspicious sequences are:
00 01 and 00 00 at offset 0x08
deadbeef at 0x18
5c 58 3d 41 41 41 41 75 43 58 3d 42 42 42 42 75 3b 5a ("\X=AAAAuCX=BBBBu;Z") at 0x41
47 49 75 at 0x89
41 41 41 41 ("AAAA") at 0x9c
ff ff ff at 0x99
00 00 00 at offset 0x36 and again at 0x3e
The first few bytes look like x86 assembly code. Trying http:/ stackoverflow.com/questions/1737095/how-do-i-disassemble-raw-x86-code (sorry, can't actually make that a link due to forum rules)
I think it's not 16-bit real mode code, so here's a static analysis of the code treated as ia32 linux code - because of the int $0x80 at the end.
Code:
objdump -D -b binary -mi386 (raw bytes here)
start:
0: eb 04 jmp 0x6
might_be_data1:
2: af scas %es:(%edi),%eax
3: c2 bf a3 ret $0xa3bf
init:
6: 81 ec 00 01 00 00 sub $0x100,%esp
c: 31 c9 xor %ecx,%ecx
search_for_zero_byte:
e: 88 0c 0c mov %cl,(%esp,%ecx,1)
11: fe c1 inc %cl
13: 75 f9 jne 0xe
15: 31 c0 xor %eax,%eax
17: ba ef be ad de mov $0xdeadbeef,%edx
checksum_loop:
1c: 02 04 0c add (%esp,%ecx,1),%al
1f: 00 d0 add %dl,%al
21: c1 ca 08 ror $0x8,%edx ; first time through, %edx = $0xdeadbe
24: 8a 1c 0c mov (%esp,%ecx,1),%bl
27: 8a 3c 04 mov (%esp,%eax,1),%bh
2a: 88 1c 04 mov %bl,(%esp,%eax,1) ; swap byte values
2d: 88 3c 0c mov %bh,(%esp,%ecx,1) ; swap byte values
30: fe c1 inc %cl ; run the loop until %cl wraps to 0
32: 75 e8 jne 0x1c
34: e9 5c 00 00 00 jmp 0x95
sub_39:
39: 89 e3 mov %esp,%ebx
3b: 81 c3 04 00 00 00 add $0x4,%ebx
41: 5c pop %esp
42: 58 pop %eax
43: 3d 41 41 41 41 cmp $0x41414141,%eax
48: 75 43 jne 0x8d
4a: 58 pop %eax
4b: 3d 42 42 42 42 cmp $0x42424242,%eax
50: 75 3b jne 0x8d
52: 5a pop %edx
53: 89 d1 mov %edx,%ecx
55: 89 e6 mov %esp,%esi
57: 89 df mov %ebx,%edi
59: 29 cf sub %ecx,%edi
5b: f3 a4 rep movsb %ds:(%esi),%es:(%edi)
5d: 89 de mov %ebx,%esi
5f: 89 d1 mov %edx,%ecx
61: 89 df mov %ebx,%edi
63: 29 cf sub %ecx,%edi
65: 31 c0 xor %eax,%eax
67: 31 db xor %ebx,%ebx
69: 31 d2 xor %edx,%edx
6b: fe c0 inc %al
6d: 02 1c 06 add (%esi,%eax,1),%bl
70: 8a 14 06 mov (%esi,%eax,1),%dl
73: 8a 34 1e mov (%esi,%ebx,1),%dh
76: 88 34 06 mov %dh,(%esi,%eax,1)
79: 88 14 1e mov %dl,(%esi,%ebx,1)
7c: 00 f2 add %dh,%dl
7e: 30 f6 xor %dh,%dh
80: 8a 1c 16 mov (%esi,%edx,1),%bl
83: 8a 17 mov (%edi),%dl
85: 30 da xor %bl,%dl
87: 88 17 mov %dl,(%edi)
89: 47 inc %edi
8a: 49 dec %ecx
8b: 75 de jne 0x6b
8d: 31 db xor %ebx,%ebx
8f: 89 d8 mov %ebx,%eax
91: fe c0 inc %al
93: cd 80 int $0x80
95: 90 nop
96: 90 nop
97: e8 9d ff ff ff call 0x39
9c: 41 inc %ecx
9d: 41 inc %ecx
9e: 41 inc %ecx
9f: 41 inc %ecx
X=AAAAuCX=BBBBu;
Before i found this page, i wrote a little tool to convert hex into a readable string in pascal..
s:=#$E3+#$81+#$C3+#$04+#$00+#$00+#$00+'\X=AAAAuCX=BBBBu;Z'+#$89+#$D1+#$89+#$E6+#$89+#$DF+')'+#$CF+#$F3+#$A4+#$89+#$DE+#$89+#$D1+#$89+#$DF+')'+#$CF+'1'+#$C0+'1'+#$DB+'1'+#$D2+#$FE+#$C0+#$02+#$1C+#$06+#$8A+#$14+#$06+#$8A+'4'+#$1E+#$88+'4'+#$06+#$99+#$14+#$1E+#$00+#$F2+'0'+#$F6+#$8A+#$1C+#$16+#$8A+#$17+'0'+#$DA+#$88+#$17+'GIu'+#$DE+'1'+#$DB+#$89+#$D8+#$FE+#$C0+#$CD+#$80+#$90+#$90+#$EB+#$9D+#$FF+#$FF+#$FF+'AAAA';
and manually typed in every hex value.. before finding this site.
anyway (annoyed wasting that 20 minutes now)
\X=AAAAuCX=BBBBu;Z
That looks like a cookie?
let's suppose they are opcodes, this does not look like 0x86 have you tried a 16bit disassembler mode?
Question, is this disassemble code? or is this a captured packet? or a packet made to look like either but instead is just random crap generated by a program with a unique identifier that can be decoded...
some clue would be nice...
---------- Post added at 08:15 PM ---------- Previous post was at 08:05 PM ----------
oh and could someone move this thread? it's got nothing to do with htc lol
Here you go :-
www.canyoucrackit.co.uk/soyoudidit.asp
Sent from my GT-S5570 using xda premium
lol, that's just cheating, forget brute force, bruteforce the http request strings to find page you get sent to if you get the answer ...
shakes head, they spent all that time and they never even bothered to stop to consider producing a link on the fly after getting the answer right then deleting the computer generated webpage (tmp file)...
they need help after all! no wonder they're in need of hackers christ....
Anyway thanks for that link, but the answer would be nice, i guess we'll found out soon enough
Cheers!
So i got it.
Passphrase: Pr0t3ct!on#[email protected]*12.2011+
solution to part #1 of canyoucrackit
part2.h will be published along with solutions to the subsequent levels after 12 December 2011
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include "part2.h" // see information above
static char part1[] = {
0xeb, 0x04, 0xaf, 0xc2, 0xbf, 0xa3, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, 0x31, 0xc9, 0x88, 0x0c,
0x0c, 0xfe, 0xc1, 0x75, 0xf9, 0x31, 0xc0, 0xba, 0xef, 0xbe, 0xad, 0xde, 0x02, 0x04, 0x0c, 0x00,
0xd0, 0xc1, 0xca, 0x08, 0x8a, 0x1c, 0x0c, 0x8a, 0x3c, 0x04, 0x88, 0x1c, 0x04, 0x88, 0x3c, 0x0c,
0xfe, 0xc1, 0x75, 0xe8, 0xe9, 0x5c, 0x00, 0x00, 0x00, 0x89, 0xe3, 0x81, 0xc3, 0x04, 0x00, 0x00,
0x00, 0x5c, 0x58, 0x3d, 0x41, 0x41, 0x41, 0x41, 0x75, 0x43, 0x58, 0x3d, 0x42, 0x42, 0x42, 0x42,
0x75, 0x3b, 0x5a, 0x89, 0xd1, 0x89, 0xe6, 0x89, 0xdf, 0x29, 0xcf, 0xf3, 0xa4, 0x89, 0xde, 0x89,
0xd1, 0x89, 0xdf, 0x29, 0xcf, 0x31, 0xc0, 0x31, 0xdb, 0x31, 0xd2, 0xfe, 0xc0, 0x02, 0x1c, 0x06,
0x8a, 0x14, 0x06, 0x8a, 0x34, 0x1e, 0x88, 0x34, 0x06, 0x88, 0x14, 0x1e, 0x00, 0xf2, 0x30, 0xf6,
0x8a, 0x1c, 0x16, 0x8a, 0x17, 0x30, 0xda, 0x88, 0x17, 0x47, 0x49, 0x75, 0xde, 0x31, 0xdb, 0x89,
0xd8, 0xfe, 0xc0, 0xcd, 0x80, 0x90, 0x90, 0xe8, 0x9d, 0xff, 0xff, 0xff, 0x41, 0x41, 0x41, 0x41,
};
// code to dump the decrypted memory:
static const char dump_mem[] = {
0xba, 0x31, 0x00, 0x00, 0x00, // mov edx, 0x40
0x8d, 0x4f, 0xce, // lea ecx, [edi-0x32]
0x31, 0xdb, // xor ebx, ebx
0x43, // inc ebx (stdout)
0x31, 0xc0, // xor eax, eax
0xb0, 0x04, // add al, 0x4 - sys_write
0xcd, 0x80, // int 0x80
0x31, 0xdb, // xor ebx,ebx
0x43, // inc ebx
0x31, 0xd2, // xor edx,edx
0x42, // inc edx
0x68, 0x0a, 0x00,0x00, 0x00, // push 0xa
0x8d, 0x0c, 0x24, // lea ecx,[esp]
0xb8, 0x04, 0x00,0x00, 0x00, // mov eax, 0x4
0xcd, 0x80, // int 0x80 - sys_write
0x31, 0xdb, // xor ebx,ebx
0x31, 0xc0, // xor eax,eax
0x40, // inc eax
0xcd, 0x80, // int 0x80 - sys_exit
};
uint32_t patch_mem(char *ptr, size_t size)
{
uint32_t i;
for (i = 0; i < size; i++) {
if (*(uint16_t *)&ptr == 0x80cd) {
*(uint16_t *)&ptr = 0x45eb;
return 0;
}
}
return 1;
}
uint32_t check_arch(void)
{
struct utsname kernel_info;
uname(&kernel_info);
return strcmp(kernel_info.machine, "i686") ? 1 : 0;
}
int main(int argc, char **argv)
{
void *mem;
if (check_arch()) {
printf("[-] this program must run on a 32-bit architecture\n");
return 1;
}
printf("[*] allocating page aligned memory\n");
mem = memalign(4096, 4096);
if (!mem) {
printf("[-] error: %s\n", strerror(errno));
return 1;
}
memset(mem, 0, 4096);
printf("[*] setting page permissions\n");
if (mprotect(mem, 4096, PROT_READ | PROT_WRITE | PROT_EXEC)) {
printf("[-] error: %s\n", strerror(errno));
return 1;
}
printf("[*] copying payload\n");
memcpy(mem, part1, sizeof(part1));
memcpy(mem + sizeof(part1), part2, sizeof(part2));
memcpy(mem + sizeof(part1) + sizeof(part2), dump_mem, sizeof(dump_mem));
printf("[*] adding dump_mem payload\n");
if (patch_mem(mem, sizeof(part1))) {
printf("[-] failed to patch memory\n");
return 0;
}
printf("[*] executing payload..\n\n");
((int(*)(void))mem)();
return 0;
}
CHEERS
Craig Capel said:
lol, that's just cheating, forget brute force, bruteforce the http request strings to find page you get sent to if you get the answer ...
shakes head, they spent all that time and they never even bothered to stop to consider producing a link on the fly after getting the answer right then deleting the computer generated webpage (tmp file)...
they need help after all! no wonder they're in need of hackers christ....
Anyway thanks for that link, but the answer would be nice, i guess we'll found out soon enough
Cheers!
Click to expand...
Click to collapse
Pr0t3ct!on#[email protected]*12.2011+
that's the answer
But easy way to do it.... just use ip scaner...and put the adress below... then you see many updates in adress...2 hours of reading...but i found it
Sorry for my bad English ...
CHEERS
thx. Interesting way to learn how this works without visiting strange sites...
(although it does not seem to fit this forums purpose)

Tytung UNIMAC kernel debugging

Hello all,
I'm working on the mac address problem inherent to HD2.
For now under Magldr, it is more or less unique (more than less) ;-)
Other boot method I can't test is haret/wimo
It seems that my patch modifying the NAND(magldr) boot affects the SD boot.
I can't figure it without precise reports. I need you to use "adb" to report me some info.
Here is how to do it:
cd your/android-sdk-linux/platform-tools/
[email protected]:> ./adb shell
# uname -a
Linux localhost 2.6.32-ics_tytung_HWA_r2.3-uniMAC #7 PREEMPT Tue May 22 02:13:09 CEST 2012 armv7l GNU/Linux
# dmesg |grep -i mac
<4>[ 0.000000] Machine: htcleo
<6>[ 1.439056] Device Bluetooth MAC Address: 00:23:76:32:16:be
<6>[ 2.989105] rndis_function_bind_config MAC: 00:00:00:00:00:00
<6>[ 2.989593] usb0: MAC 36:b0:0d:af:76:1d
<6>[ 2.989624] usb0: HOST MAC ca:50:bc:14:ad:79
<6>[ 3.444152] Device Wifi Mac Address: 00:23:76:be:16:32
Tips
-shell into your hd2 asap, while in the boot animation !
-do it with both kernels HWA_r2.3-uniMAC and previous functionnal
Please other Magldr users, post here the macaddress you have.
This is just to eval 'dispersion' (collision avoidance) with actual patch.
Franck
ok, good news,
Saw the mistake in the kernel code.
function() call to guess a mac was inadvertandly removed for SD boot method!
Fixed in R4
This thread still must be filled with MAC address for NAND and SD kernel version to evaluate collision avoidance.
Meanwhile I'm working on reading on interesting NAND block with something ressembling a MAC in it.
Will need more testers to check it is a unique MAC ;-)
Hello All,
How many of you users with hd2 will be able to compile a custom kernel with a patched htcleo_nand.c ?
This is to validate my guess of finding two unique macadress writed in block 505 of the NAND.
To definitly get rid of this problem.
Franck
Code:
diff --git a/drivers/mtd/devices/htcleo_nand.c b/drivers/mtd/devices/htcleo_nand.c
index 2150bcc..bfbcbad 100755
--- a/drivers/mtd/devices/htcleo_nand.c
+++ b/drivers/mtd/devices/htcleo_nand.c
@@ -1827,6 +1827,116 @@ static int param_get_page_size(char *buffer, struct kernel_param *kp)
}
module_param_call(pagesize, NULL, param_get_page_size, NULL, S_IRUGO);
+int is_htc_mac (int pattern)
+{
+ /* HTC blocks to find :
+ 00:09:2D
+ 00:23:76
+ 18:87:76
+ 1C:B0:94
+ 38:E7:D8
+ 64:A7:69
+ 7C:61:93
+ 90:21:55
+ A0:F4:50
+ A8:26:D9
+ D4:20:6D
+ D8:B3:77
+ E8:99:C4
+ F8:DB:F7 */
+ static int nums[] = {
+ 0x00092D,0x2D0900,
+ 0x002376,0x762300,
+ 0x188776,0x768718,
+ 0x1CB094,0x94B01C,
+ 0x38E7D8,0xD8E738,
+ 0x64A769,0x69A764,
+ 0x7C6193,0x93617C,
+ 0x902155,0x552190,
+ 0xA0F450,0x50F4A0,
+ 0xA826D9,0xD926A8,
+ 0xD4206D,0x6D20D4,
+ 0xD8B377,0x77B3D8,
+ 0xE899C4,0xC499E8,
+ 0xF8DBF7,0xF7DBF8};
+ int i;
+ for (i=0; i< (sizeof(nums)/sizeof(nums[0])); i++)
+ {
+ if (nums[i] == pattern) return 1;
+ }
+ return 0;
+}
+void scanmac(struct mtd_info *mtd)
+{
+ unsigned char *iobuf;
+ int ret;
+ loff_t addr;
+ struct mtd_oob_ops ops;
+ int i,j,k;
+
+ iobuf = kmalloc(2048/*mtd->erasesize*/, GFP_KERNEL);
+ if (!iobuf) {
+ /*ret = -ENOMEM;*/
+ printk("%s: error: cannot allocate memory\n",__func__);
+ return;
+ }
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.len = 2048;
+ ops.datbuf = iobuf;
+ ops.ooblen = 0;
+ ops.oobbuf = NULL;
+ ops.retlen = 0;
+
+ /* bloc 505 page 6 contains as good candidate */
+ addr = ((loff_t) 505*0x20000 + 6*2048);
+ ret = msm_nand_read_oob(mtd, addr, &ops);
+
+ if (ret == -EUCLEAN)
+ ret = 0;
+ if (ret || ops.retlen != 2048 ) {
+ printk("%s: error: read(%d) failed at %#llx\n",__func__,ops.retlen, addr);
+ goto out;
+ }
+
+ printk("%s: Prefered candidate mac=%02x:%02x:%02x:%02x:%02x:%02x\n",__func__,
+ iobuf[5],iobuf[4],iobuf[3],iobuf[2],iobuf[1],iobuf[0]);
+
+ /* now lets walk looking for HTC mac in the first reserved blocks of NAND */
+ /* NUM_PROTECTED_BLOCKS=0x212 but Parttiontable starts at 0x219 */
+ /* I think 400 is ok, I have already eliminated 0 - 157 with false positive */
+ /* If my guess is correct, only 505 will match ;-) */
+ for (i=158; i<0x219; i++) {
+ for (j=0; j<64; j++) {
+ addr = ((loff_t) i*0x20000 + j*2048);
+ ret = msm_nand_read_oob(mtd, addr, &ops);
+
+ if (ret == -EUCLEAN)
+ ret = 0;
+ if (ret || ops.retlen != 2048 ) {
+ printk("%s: error: read(%d) failed at %#llx\n",__func__,ops.retlen, addr);
+ break;
+ }
+ /* check */
+ for (k=0; k<2045; k++) {
+ if (is_htc_mac( (iobuf[k+0]<<16) + (iobuf[k+1]<<8) + iobuf[k+2])) {
+ printk("Mac candidate at block:%d page:%d offset:%d:\n",i,j,k);
+ k >>= 4;
+ k <<= 4;
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, &iobuf[k], 16);
+ k += 16;
+ }
+ }
+ }/*j*/
+ }/*i*/
+ ret = 0;
+out:
+ kfree(iobuf);
+ if (ret)
+ printk("Find MAc Error %d occurred\n", ret);
+ return;
+}
+
/**
* msm_nand_scan - [msm_nand Interface] Scan for the msm_nand device
* @param mtd MTD device structure
@@ -1992,6 +2102,8 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
/* msm_nand_unlock_all(mtd); */
/* return this->scan_bbt(mtd); */
+ scanmac(mtd);
+
#if VERBOSE
for (i=0;i<nand_info->block_count;i++)
my findings are on five HD2 are:
Frk
Mac candidate at block:505 page:0 offset:40:
00000000: 00 00 00 00 30 00 00 00 38 e7 d8 e6 38 fc 00 00 ....0...8...8...
Mac candidate at block:505 page:6 offset:3:
00000000: 80 1c e2 d8 e7 38 ff ff ff ff ff ff ff ff ff ff .....8..........
wifi mac 38 e7 d8 e6 38 fcunder WIMO
Bad
Mac candidate at block:505 page:0 offset:40:
00000000: 00 00 00 00 30 00 00 00 00 23 76 5d fb 08 00 00 ....0....#v]....
Mac candidate at block:505 page:6 offset:3:
00000000: df 20 74 76 23 00 ff ff ff ff ff ff ff ff ff ff . tv#...........
Frk2
Mac candidate at block:505 page:0 offset:40:
00000000: 00 00 00 00 30 00 00 00 00 23 76 d7 ea 13 00 00 ....0....#v.....
Mac candidate at block:505 page:6 offset:3:
00000000: 80 5b e5 76 23 00 ff ff ff ff ff ff ff ff ff ff .[.v#...........
Val
Mac candidate at block:505 page:0 offset:40:
00000000: 00 00 00 00 30 00 00 00 00 23 76 89 09 c0 00 00 ....0....#v.....
Mac candidate at block:505 page:6 offset:3:
00000000: 46 da 6d 76 23 00 ff ff ff ff ff ff ff ff ff ff F.mv#...........
Flo
Mac candidate at block:505 page:0 offset:40:
00000000: 00 00 00 00 30 00 00 00 00 23 76 8c a4 a6 00 00 ....0....#v.....
Mac candidate at block:505 page:6 offset:3:
00000000: 3d 48 6f 76 23 00 ff ff ff ff ff ff ff ff ff ff =Hov#...........
Flo after full task29+reinstall
Mac candidate at block:505 page:0 offset:40:
00000000: 00 00 00 00 30 00 00 00 00 23 76 8c a4 a6 00 00 ....0....#v.....
Mac candidate at block:505 page:6 offset:3:
00000000: 3d 48 6f 76 23 00 ff ff ff ff ff ff ff ff ff ff =Hov#...........
I think you nailed it,
My device's bluetooth mac id under windows: 00:23:76:78:70:78
My device's wireless mac id under windows: 00:23:76:96:1B:F9
Code:
<4>[ 1.325286] scanmac: Prefered candidate mac=00:23:76:78:70:78
<4>[ 22.797302] Mac candidate at block:505 page:0 offset:40:
<7>[ 22.797332] 00000000: 00 00 00 00 10 00 00 00 [B]00 23 76 96 1b f9[/B] 00 00
<4>[ 22.803070] Mac candidate at block:505 page:6 offset:3:
<7>[ 22.803100] 00000000: [B]78 70 78 76 23 00[/B] ff ff ff ff ff ff ff ff ff ff
Although there was another candidate,
Code:
<4>[ 24.686889] Mac candidate at block:536 page:5 offset:443:
<7>[ 24.686950] 00000000: bf 03 1e ad ba 9d 4a 6f a4 e1 89 7c 61 93 67 d9
But this one is totally wrong, block:536 is after the bootloader(clk in this case) and is part of the config table
As i said in the email, you should only scan till block 530 (0x212)
EDIT: modified your code a bit,
Code:
<4>[ 1.325347] scanmac: candidate for wifi mac=00:23:76:96:1b:f9
<4>[ 1.325622] scanmac: candidate for bluetooth mac=00:23:76:78:70:78
Code:
diff --git a/drivers/mtd/devices/htcleo_nand.c b/drivers/mtd/devices/htcleo_nand.c
index e4e347e..27aa6e8 100755
--- a/drivers/mtd/devices/htcleo_nand.c
+++ b/drivers/mtd/devices/htcleo_nand.c
@@ -1835,6 +1835,54 @@ static int param_get_page_size(char *buffer, struct kernel_param *kp)
}
module_param_call(pagesize, NULL, param_get_page_size, NULL, S_IRUGO);
+void scanmac(struct mtd_info *mtd)
+{
+ unsigned char *iobuf;
+ int ret;
+ loff_t addr;
+ struct mtd_oob_ops ops;
+
+ iobuf = kmalloc(2048/*mtd->erasesize*/, GFP_KERNEL);
+ if (!iobuf) {
+ printk("%s: error: cannot allocate memory\n",__func__);
+ return;
+ }
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.len = 2048;
+ ops.datbuf = iobuf;
+ ops.ooblen = 0;
+ ops.oobbuf = NULL;
+ ops.retlen = 0;
+
+ addr = ((loff_t) 505*0x20000);
+ ret = msm_nand_read_oob(mtd, addr, &ops);
+ if (ret == -EUCLEAN)
+ ret = 0;
+ if (ret || ops.retlen != 2048 ) {
+ printk("%s: error: read(%d) failed at %#llx\n",__func__,ops.retlen, addr);
+ goto out;
+ }
+ printk("%s: candidate for wifi mac=%02x:%02x:%02x:%02x:%02x:%02x\n",__func__,
+ iobuf[40],iobuf[41],iobuf[42],iobuf[43],iobuf[44],iobuf[45]);
+
+ addr = ((loff_t) 505*0x20000 + 6*0x800);
+ ret = msm_nand_read_oob(mtd, addr, &ops);
+ if (ret == -EUCLEAN)
+ ret = 0;
+ if (ret || ops.retlen != 2048 ) {
+ printk("%s: error: read(%d) failed at %#llx\n",__func__,ops.retlen, addr);
+ goto out;
+ }
+ printk("%s: candidate for bluetooth mac=%02x:%02x:%02x:%02x:%02x:%02x\n",__func__,
+ iobuf[5],iobuf[4],iobuf[3],iobuf[2],iobuf[1],iobuf[0]);
+ ret = 0;
+out:
+ kfree(iobuf);
+ if (ret) printk("Find MAC Error %d occurred\n", ret);
+ return;
+}
+
/**
* msm_nand_scan - [msm_nand Interface] Scan for the msm_nand device
* @param mtd MTD device structure
@@ -2000,6 +2048,7 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
/* msm_nand_unlock_all(mtd); */
/* return this->scan_bbt(mtd); */
+ scanmac(mtd);
#if VERBOSE
for (i=0;i<nand_info->block_count;i++)
Great job.
I've implemented the mac address reading in my kernel. You can see the commit here:
https://github.com/marc1706/desire_kernel_35/commit/0b249dfba877b96fc0ebe1333738f0920b4dc7c5
edit:
My mac addresses, now both with Windows Mobile and with Android:
Code:
Wifi Mac: 00:23:76:8A:40:B9
BT Mac: 00:23:76:6E:4B:C6
well, I'l sure now that the offset [40...45] have a macaddress.
problem is how is it unique....
If you read this code you will see that when the Nand is blank, a default macaddress of 00:90:4C:C5:00:34 is created.
Code:
ROM:95043CC8 @ =============== S U B R O U T I N E =======================================
ROM:95043CC8
ROM:95043CC8 @ 1 initdata
ROM:95043CC8 @ 0 displaydata
ROM:95043CC8
ROM:95043CC8 eMapiCheckWlanDataValidity: @ CODE XREF: StartupSequence+3Cp
ROM:95043CC8 @ Emapitest:loc_9502020Cp
ROM:95043CC8 @ DATA XREF: ...
ROM:95043CC8
ROM:95043CC8 var_30 = -0x30
ROM:95043CC8 var_2C = -0x2C
ROM:95043CC8 var_28 = -0x28
ROM:95043CC8
ROM:95043CC8 STMFD SP!, {R4-R11,LR}
ROM:95043CCC SUB SP, SP, #0xC
ROM:95043CD0 MOV R4, R0
ROM:95043CD4 LDR R0, =WlanBlock
ROM:95043CD8 MOV R5, #0
ROM:95043CDC BL GetWLANblock
ROM:95043CE0 BL CheckSignature
ROM:95043CE4 LDR R7, =0xEE4329
ROM:95043CE8 MOV R6, R0
ROM:95043CEC CMP R4, #0
ROM:95043CF0 BNE _InitData
ROM:95043CF4 LDR R3, [R6]
ROM:95043CF8 CMP R3, R7
ROM:95043CFC BNE _InitData
ROM:95043D00 LDR R3, [R6,#4]
ROM:95043D04 CMP R3, #0
ROM:95043D08 BEQ _err_invalid_update
ROM:95043D0C LDR R3, [R6,#8]
ROM:95043D10 CMP R3, #0
ROM:95043D14 BEQ _err_invalid_update
ROM:95043D18 LDR R2, [R6,#0xC]
ROM:95043D1C CMP R2, #0x7C0
ROM:95043D20 BLS loc_95043D30
ROM:95043D24
ROM:95043D24 _err_invalid_body_size: @ "[eMapiCheckWlanDataValidity] Invalid bo"...
ROM:95043D24 LDR R0, =aEmapicheckwlan
ROM:95043D28 BL print
ROM:95043D2C B _end
ROM:95043D30 @ ---------------------------------------------------------------------------
ROM:95043D30
ROM:95043D30 loc_95043D30: @ CODE XREF: eMapiCheckWlanDataValidity+58j
ROM:95043D30 AND R3, R2, #3
ROM:95043D34 SUB R3, R2, R3
ROM:95043D38 ADD R1, R3, #4
ROM:95043D3C MOV R2, #0
ROM:95043D40 ADD R0, R6, #0x40
ROM:95043D44 BL GetRamCrc
ROM:95043D48 LDR R3, [R6,#0x10]
ROM:95043D4C CMP R0, R3
ROM:95043D50 BEQ _DisplayData
ROM:95043D54
ROM:95043D54 _err_checsum_invalid: @ "[eMapiCheckWlanDataValidity] CheckSum e"...
ROM:95043D54 LDR R0, =aEmapicheckwl_0
ROM:95043D58 BL print
ROM:95043D5C B _end
ROM:95043D60 @ ---------------------------------------------------------------------------
ROM:95043D60
ROM:95043D60 _DisplayData: @ CODE XREF: eMapiCheckWlanDataValidity+88j
ROM:95043D60 LDR R0, =aWlanDataHeader @ "Wlan data header ++++++++++++++++++++\n"
ROM:95043D64 BL print
ROM:95043D68 LDR R1, [R6]
ROM:95043D6C LDR R0, =aSignature0xX @ "Signature : 0x%x\n"
ROM:95043D70 BL printf
ROM:95043D74 LDR R1, [R6,#4]
ROM:95043D78 LDR R0, =aUpdatestatus0x @ "UpdateStatus : 0x%x\n"
ROM:95043D7C BL printf
ROM:95043D80 LDR R1, [R6,#8]
ROM:95043D84 LDR R0, =aUpdatecount0xX @ "UpdateCount : 0x%x\n"
ROM:95043D88 BL printf
ROM:95043D8C LDR R1, [R6,#0xC]
ROM:95043D90 LDR R0, =aBodylength0xX @ "BodyLength : 0x%x\n"
ROM:95043D94 BL printf
ROM:95043D98 LDR R1, [R6,#0x10]
ROM:95043D9C LDR R0, =aBodycrc0xX @ "BodyCRC : 0x%x\n"
ROM:95043DA0 BL printf
ROM:95043DA4 LDR R1, [R6,#0x14]
ROM:95043DA8 LDR R0, =aAdieid00xX @ "aDieId(0) : 0x%x\n"
ROM:95043DAC BL printf
ROM:95043DB0 LDR R1, [R6,#0x18]
ROM:95043DB4 LDR R0, =aAdieid10xX @ "aDieId(1) : 0x%x\n"
ROM:95043DB8 BL printf
ROM:95043DBC LDR R1, [R6,#0x1C]
ROM:95043DC0 LDR R0, =aAdieid20xX @ "aDieId(2) : 0x%x\n"
ROM:95043DC4 BL printf
ROM:95043DC8 LDR R1, [R6,#0x20]
ROM:95043DCC LDR R0, =aAdieid30xX @ "aDieId(3) : 0x%x\n"
ROM:95043DD0 BL printf
ROM:95043DD4 LDR R1, [R6,#0x24]
ROM:95043DD8 LDR R0, =aCountryid0xX @ "countryID : 0x%x\n"
ROM:95043DDC BL printf
ROM:95043DE0 LDRB LR, [R6,#45]
ROM:95043DE4 LDRB R4, [R6,#44]
ROM:95043DE8 LDRB R5, [R6,#43]
ROM:95043DEC LDRB R3, [R6,#42]
ROM:95043DF0 LDRB R2, [R6,#41]
ROM:95043DF4 LDRB R1, [R6,#40]
ROM:95043DF8 LDR R0, =aMacBBBBBB @ "MAC= %B %B %B %B %B %B\r\n "
ROM:95043DFC STR LR, [SP,#0x30+var_28]
ROM:95043E00 STR R4, [SP,#0x30+var_2C]
ROM:95043E04 STR R5, [SP,#0x30+var_30]
ROM:95043E08 BL printf
ROM:95043E0C LDR R0, =aWlanDataHead_0 @ "Wlan data header ----------------------"...
ROM:95043E10
ROM:95043E10 _ok: @ CODE XREF: eMapiCheckWlanDataValidity+1F4j
ROM:95043E10 BL print
ROM:95043E14 MOV R5, #1
ROM:95043E18 B _end
ROM:95043E1C @ ---------------------------------------------------------------------------
ROM:95043E1C
ROM:95043E1C _err_invalid_update: @ CODE XREF: eMapiCheckWlanDataValidity+40j
ROM:95043E1C @ eMapiCheckWlanDataValidity+4Cj
ROM:95043E1C LDR R0, =aEmapicheckwl_1 @ "[eMapiCheckWlanDataValidity] Invalid up"...
ROM:95043E20 BL print
ROM:95043E24 B _end
ROM:95043E28 @ ---------------------------------------------------------------------------
ROM:95043E28
ROM:95043E28 _InitData: @ CODE XREF: eMapiCheckWlanDataValidity+28j
ROM:95043E28 @ eMapiCheckWlanDataValidity+34j
ROM:95043E28 MOV R2, #0x800 @ Count
ROM:95043E2C MOV R1, #0 @ char
ROM:95043E30 MOV R0, R6 @ int
ROM:95043E34 BL fillchar
ROM:95043E38
ROM:95043E38
ROM:95043E38 MOV R3, #0x238
ROM:95043E3C LDR R1, =unk_97901318
ROM:95043E40 ORR R3, R3, #2
ROM:95043E44 MOV R5, #0x10
ROM:95043E48 MOV R8, #0x90 @ '�'
ROM:95043E4C MOV R9, #0x4C @ 'L'
ROM:95043E50 MOV R10, #0xC5 @ '+'
ROM:95043E54 MOV R11, #0x34 @ '4'
ROM:95043E58 MOV LR, #1
ROM:95043E5C MOV R4, #0
ROM:95043E60 MOV R2, R3
ROM:95043E64 ADD R0, R6, #0x40
ROM:95043E68 STMIA R6, {R7,LR}
ROM:95043E6C STR LR, [R6,#8]
ROM:95043E70 STR R3, [R6,#0xC]
ROM:95043E74 STR R5, [R6,#0x24]
ROM:95043E78 STRB R4, [R6,#0x28]
ROM:95043E7C STRB R8, [R6,#0x29]
ROM:95043E80 STRB R9, [R6,#0x2A]
ROM:95043E84 STRB R10, [R6,#0x2B]
ROM:95043E88 STRB R4, [R6,#0x2C]
ROM:95043E8C STRB R11, [R6,#0x2D]
ROM:95043E90 BL memcpy
ROM:95043E94 MOV R2, #0
ROM:95043E98 MOV R1, #0x23C
ROM:95043E9C ADD R0, R6, #0x40
ROM:95043EA0 BL GetRamCrc
ROM:95043EA4 MOV R3, R0
ROM:95043EA8 MOV R0, R6
ROM:95043EAC STR R3, [R6,#0x10]
ROM:95043EB0 BL callNAND_WriteConfig
ROM:95043EB4 CMP R0, #0
ROM:95043EB8 LDRNE R0, =aInitializeWlan @ "Initialize wlan data success\n"
ROM:95043EBC BNE _ok
ROM:95043EC0
ROM:95043EC0 _err_init_failed: @ "Initialize wlan data fail\n\n"
ROM:95043EC0 LDR R0, =aInitializeWl_0
ROM:95043EC4 BL print
ROM:95043EC8 MOV R5, #0
ROM:95043ECC
ROM:95043ECC _end: @ CODE XREF: eMapiCheckWlanDataValidity+64j
ROM:95043ECC @ eMapiCheckWlanDataValidity+94j ...
ROM:95043ECC MOV R0, R5
ROM:95043ED0 ADD SP, SP, #0xC
ROM:95043ED4 LDMFD SP!, {R4-R11,LR}
ROM:95043ED8 BX LR
Is that from a ROM? If yes then I'm guessing that it maybe creates a "default" mac before the actual mac address is parsed from SPL.
I've done a task29 and installed a (close to) stock windows mobile ROM before checking my real wifi and bt mac addresses.
And they are the same as the ones this code returns.
marc1706 said:
Is that from a ROM? If yes then I'm guessing that it maybe creates a "default" mac before the actual mac address is parsed from SPL.
I've done a task29 and installed a (close to) stock windows mobile ROM before checking my real wifi and bt mac addresses.
And they are the same as the ones this code returns.
Click to expand...
Click to collapse
It is from SPL, But since nand config data is never erased and is written in factory, i think it should be fine using this as a source, since we know there weren't any mac collisions under windows mobile as far as i know.
Add another htc-hd2 I got
Directly installed with Tytung kernel hwa v2.3 (jun 2012), macaddress:
wifi : 00:23:76:89:1F:B2
bluetooth : 00:23:76:6D:E3:FF
are unique :angel:
Franck
Franck78 said:
Add another htc-hd2 I got
Directly installed with Tytung kernel hwa v2.3 (jun 2012), macaddress:
wifi : 00:23:76:89:1F:B2
bluetooth : 00:23:76:6D:E3:FF
are unique :angel:
Franck
Click to expand...
Click to collapse
I've confirmed this fix with 4 different HD2 devices - all are unique, and show the same MAC from WinMo65 Thanks a ton for your work!!!

[Guide] Patch libandroid_runtime to allow suhide to work. (Pixel/Pixel XL)

This thread is about hiding root. Feel free to discuss anything ranging from MagiskHide to suhide. See the suhide patching instructions below.
Introduction:
With the November security patches, Google back-ported a security feature that allows only a certain whitelist of filesystem sockets to be used.
This is the same feature that prevents suhide from working.
This particular commit is here:
https://android.googlesource.com/pl...8be33b0bedec211708c4525b9d3f3b4effb385c^!/#F0
If you are building CM or AOSP, all you need to do is revert this commit.
However, for binary builds a more direct patching approach is needed.
As I said earlier:
Fenny said:
The basis of my binary patches is to remove the function calls to
Code:
RuntimeAbort(JNIEnv* env, int line, const char* msg)
and remove a later reference to
Code:
gOpenFdTable
that was causing a crash.
Click to expand...
Click to collapse
ARM
Let me get into a bit more detail, and we can start with the error message that zygote spits out with an unpatched version of the file:
"Unable to construct file descriptor table"
We see that in the commit here:
Code:
+ // Close any logging related FDs before we start evaluating the list of
+ // file descriptors.
+ __android_log_close();
+
+ // If this is the first fork for this zygote, create the open FD table.
+ // If it isn't, we just need to check whether the list of open files has
+ // changed (and it shouldn't in the normal case).
+ if (gOpenFdTable == NULL) {
+ gOpenFdTable = FileDescriptorTable::Create();
+ if (gOpenFdTable == NULL) {
+ RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
+ }
+ } else if (!gOpenFdTable->Restat()) {
+ RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
+ }
+
pid_t pid = fork();
When searching for references to the string in the disassembly of the file:
Code:
.text:000C8CC8 ADD R2, PC ; "Unable to construct file descriptor tab"...
.text:000C8CCA B loc_C8CDE
.text:000C8CCC BL sub_C845C
.text:000C8CD0 CBNZ R0, loc_C8CE2
.text:000C8CD2 LDR.W R2, =(aUnableToRestat - 0xC8CE0)
.text:000C8CD6 MOV R0, R4
.text:000C8CD8 MOV.W R1, #0x1D6
.text:000C8CDC ADD R2, PC ; "Unable to restat file descriptor table."
.text:000C8CDE BL sub_C873C
.text:000C8CE2 BLX fork
So, we're looking at the instruction "BL sub_C873C" as "RuntimeAbort" we know it's the right one because it is a conditional call just before the fork.
Which in hex is:
Code:
FF F7 2D FD
The simplest patch is to remove the function call entirely by replacing this with the arm equivalent of nop.
Code:
00 00 00 00
However, that breaks things because the file descriptor variable now contains a null where a reference should be.
Code:
.text:000C8D08 LDR.W R0, [R12]
.text:000C8D0C LDR.W R9, [R0,#8] ; <- Crash happens here.
.text:000C8D10 CMP.W R9, #0
.text:000C8D14 BEQ loc_C8D38
Hex:
Code:
DC F8 00 00 D0 F8 08 90 B9 F1 00 0F
So, since we always need to take the BEQ branch, we're going to replace the whole lot of functions with:
Code:
.text:000C8D08 MOVS R0, #0
.text:000C8D0A MOVS R0, #0
.text:000C8D0C MOVS R0, #0
.text:000C8D0E MOVS R0, #0
.text:000C8D10 MOVS R0, #0
.text:000C8D12 CMP R0, #0
Hex:
Code:
00 20 00 20 00 20 00 20 00 20 00 28
ARM64
The ARM64 patches are the same idea, but different opcodes:
In this example sub_881B8 calls our RuntimeAbort function, so first we nop out the call to that.
Replace:
Code:
.text:000000000014EF8C ADD X2, X27, #[email protected] ; "Socket name not whitelisted : %s (fd=%d"...
.text:000000000014EF90 MOV W4, W20
.text:000000000014EF94 MOV W0, #6
.text:000000000014EF98 MOV X19, #0
[B].text:000000000014EF9C BL sub_881B8[/B]
.text:000000000014EFA0 B loc_14ECA0
Hex:
Code:
87 E4 FC 97
Replace with:
Code:
.text:000000000014EF8C ADD X2, X27, #[email protected] ; "Socket name not whitelisted : %s (fd=%d"...
.text:000000000014EF90 MOV W4, W20
.text:000000000014EF94 MOV W0, #6
.text:000000000014EF98 MOV X19, #0
[B].text:000000000014EF9C NOP[/B]
.text:000000000014EFA0 B loc_14ECA0
Hex:
Code:
1F 20 03 D5
Next, we patch away the crash:
We want to take the CBZ X23, loc_151AC0 jump.
Replace:
Code:
.text:00000000001510CC ADRP X9, #[email protected]
.text:00000000001510D0 LDR X10, [X9,#[email protected]]
[B].text:00000000001510D4 LDR X23, [X10,#0x10][/B]
.text:00000000001510D8 CBZ X23, loc_151AC0
.text:00000000001510DC LDR X19, [X23,#0x18]
.text:00000000001510E0 CBZ X19, loc_1511F4
.text:00000000001510E4 BL sub_88468
.text:00000000001510E8 MOV X22, X0
.text:00000000001510EC ADRP X11, #[email protected] ; "/dev/null"
.text:00000000001510F0 ADD X24, X11, #[email protected] ; "/dev/null"
.text:00000000001510F4 B loc_151174
Hex:
Code:
57 09 40 F9
Replace with:
Code:
.text:00000000001510CC ADRP X9, #[email protected]
.text:00000000001510D0 LDR X10, [X9,#[email protected]]
[B].text:00000000001510D4 MOV X23, #0[/B]
.text:00000000001510D8 CBZ X23, loc_151AC0
.text:00000000001510DC LDR X19, [X23,#0x18]
.text:00000000001510E0 CBZ X19, loc_1511F4
.text:00000000001510E4 BL sub_88468
.text:00000000001510E8 MOV X22, X0
.text:00000000001510EC ADRP X11, #[email protected] ; "/dev/null"
.text:00000000001510F0 ADD X24, X11, #[email protected] ; "/dev/null"
.text:00000000001510F4 B loc_151174
Hex:
Code:
17 00 80 D2
Finally, nop out the second call to RuntimeAbort (ARM optimized these two calls into one, whereas arm64 split them into two subfunctions.)
Replace:
Code:
.text:0000000000151AAC MOV X0, X25
.text:0000000000151AB0 MOV W1, #0x1D3
.text:0000000000151AB4 ADD X2, X4, #[email protected] ; "Unable to construct file descriptor tab"...
[B].text:0000000000151AB8 BL sub_150264[/B]
.text:0000000000151ABC B loc_150F10
Hex:
Code:
EB F9 FF 97
Replace with:
Code:
.text:0000000000151AAC MOV X0, X25
.text:0000000000151AB0 MOV W1, #0x1D3
.text:0000000000151AB4 ADD X2, X4, #[email protected] ; "Unable to construct file descriptor tab"...
[B].text:0000000000151AB8 NOP[/B]
.text:0000000000151ABC B loc_150F10
Code:
1F 20 03 D5
TL;DR
I have this working on 7.1/7.1.1.
The gist:
Patching ART binaries required. System modification required. (can't bind mount modified ART or suhide breaks).
Known issues:
UI prompts to allow new or updated root apps do not display when suhide is enabled. (7.1.1+)
SuperSU 2.79 SR1 and above use incompatible selinux contexts with Suhide 0.55 and below.
JAYNO20 said:
I can confirm this works on the 5" Pixel device as well. This is NOT limited to just the XL.
Click to expand...
Click to collapse
Downloads:
Here are a couple patched versions:
libandroid_runtime_pixelxl_NDE63V.tar
libandroid_runtime_pixelxl_NMF26O.tar
libandroid_runtime_pixelxl_NMF26Q.tar
libandroid_runtime_pixelxl_NOF26V.tar (Reported working with NOF27B/C, N2G47E/J/K)
You WILL need to match your builds up.
Finally!
Cant wait for the write up!
ghostENVY said:
Finally!
Cant wait for the write up!
Click to expand...
Click to collapse
Well, since you can't wait... I will do a full write-up when I get home, until then, you can grab the modded Android runtime files from NDE63V: libandroid_runtime_pixelxl_NDE63V.tar
Basic process is: Replace modded files in system, fix permissions, flash suhide.
Will this work on NMF26Q?
Also, NMF26O?
Ker~Man said:
Will this work on NMF26Q?
Click to expand...
Click to collapse
JAYNO20 said:
Also, NMF26O?
Click to expand...
Click to collapse
ART libs look like they can be patched for both of those builds, but I haven't done them yet.
The old libs I posted probably won't set your phone on fire, but it is very likely you would have weird issues even if it doesn't just bootloop, which is what I would expect to happen.
JAYNO20 said:
Also, NMF26O?
Click to expand...
Click to collapse
So, after replacing the first of the four files, my phone froze immediately and now boots to an all black screen. Just fu**ing great...
Any ideas other than a full flash of stock???
Fenny said:
ART libs look like they can be patched for both of those builds, but I haven't done them yet.
The old libs I posted probably won't set your phone on fire, but it is very likely you would have weird issues even if it doesn't just bootloop, which is what I would expect to happen.
Click to expand...
Click to collapse
Any chance you'll get around to patching those as well?
JAYNO20 said:
Any chance you'll get around to patching those as well?
Click to expand...
Click to collapse
+1. Would be really nice...
Ker~Man said:
+1. Would be really nice...
Click to expand...
Click to collapse
I'd love to be able to use Android Pay again...
Ker~Man said:
So, after replacing the first of the four files, my phone froze immediately and now boots to an all black screen. Just fu**ing great...
Any ideas other than a full flash of stock???
Click to expand...
Click to collapse
Yeah, you're not going to be able to replace those files while you're booted into the normal system.
If you have a backup of the file restore it in recovery. If not, you'll probably need to flash a stock system partition.
It is likely that you did not get a chance to set permissions on the file when you replaced it. You can try going into recovery and try setting the correct owner and permissions on the file.
I'm so looking forward to this write up, thank you for your work!
Great job!
The anticipation is killing me
MyNarwhalBacon said:
The anticipation is killing me
Click to expand...
Click to collapse
Likewise!
Added some patched versions to the OP.
Write-up still pending. Working on an auto patcher for the files.
Fenny said:
Added some patched versions to the OP.
Write-up still pending. Working on an auto patcher for the files.
Click to expand...
Click to collapse
Nice work. Will the Q files work with the O update?
---------- Post added at 02:47 AM ---------- Previous post was at 02:34 AM ----------
Also, will this be ok to flash to the Pixel? (NOT XL)
Hi, great work. Is it doable for other brands (Sammy, Moto, Huawei...)? Any advice, paths to follow? Thx
Echoe™ team member / S7E
I tried on O update, bootloops.
You sir are the man. I'm excited to be able to root and still play Pokemon go

Root with CVE-2019-2215?

Anyone have any luck running [the poc exploit](https://forum.xda-developers.com/ga...ompiled-executed-zero-day-exploitcve-t3978059) for CVE-2019-2215 on an Oreo LG V20? It's listed as one of the affected devices in the news reports. I'd love to get even a temp root.
For me (LS997) the poc stops with writev returning 0x1000 (it should return 0x2000 if the poc is working).
I have played around with the poc.c source code and noticed that if I change WAITQUEUE_OFFSET to 0x90, the device crashes and reboots. Since an untrusted app isn't supposed to be able to reboot a device, this suggests that there may be an exploitable thing around there somewhere.
Looking at the kernel source on the LG site (at least for the LS997), the LGV20 does have the bug in the kernel. However, the LGV20's kernel has a different layout of struct binder_thread than the version of the kernel the poc is designed for. And unfortunately it's not just a trivial fix, because the poc assumes the waitqueue field is 16-byte aligned, while on the LGV20 it's only 8-byte aligned (because there is one less field in the struct). There is probably a way around this, but I am not good at this sort of stuff: I don't really understand how the poc works. If anybody here does, maybe we can pool our minds and work together.
arpruss said:
Looking at the kernel source on the LG site (at least for the LS997), the LGV20 does have the bug in the kernel. However, the LGV20's kernel has a different layout of struct binder_thread than the version of the kernel the poc is designed for. And unfortunately it's not just a trivial fix, because the poc assumes the waitqueue field is 16-byte aligned, while on the LGV20 it's only 8-byte aligned (because there is one less field in the struct). There is probably a way around this, but I am not good at this sort of stuff: I don't really understand how the poc works. If anybody here does, maybe we can pool our minds and work together.
Click to expand...
Click to collapse
what is the waitqueue offset in the binder_thread struct in your kernel?
chompie1337 said:
what is the waitqueue offset in the binder_thread struct in your kernel?
Click to expand...
Click to collapse
0x98=152, assuming the kernel source I downloaded is correct and assuming I counted all the fields right. Here is my count (counting 64-bits at a time):
Code:
struct binder_thread {
struct binder_proc *proc; // 1
struct rb_node rb_node; // 4
struct list_head waiting_thread_node; // 6
int pid;
int looper; /* only modified by this thread */ // 7
bool looper_need_return; /* can be written by other thread */ // 8
struct binder_transaction *transaction_stack; // 9
struct list_head todo; // 11
struct binder_error return_error; // 15
struct binder_error reply_error; // 19
wait_queue_head_t wait; // spinlock_t + list_head
struct binder_stats stats;
atomic_t tmp_ref;
bool is_dead;
struct task_struct *task;
};
hmm. i see what you mean by alignment now.
this define
Code:
#define IOVEC_ARRAY_SZ (BINDER_THREAD_SZ / 16) //25
makes me believe that the size of iovec_array[ IOVEC_ARRAY_SZ] defined on line 75, has to equal size of struct binder_thread this is because somehow, the contents iovec_array overwrites the contents of a binder_thread structure. which means, that iovec_array[IOVEC_INDX_FOR_WQ] should contain the contents of binder_thread->wait.
wait_queue_head is defined as:
Code:
struct wait_queue_head {
spinlock_t lock;
struct list_head head;
};
meaning you have to make sure that the values in iovec_array[IOVEC_INDX_FOR_WQ] correspond correctly to the wait_queue_head but also line up so the writev works. there's definitely some trickery you could do to make this work. my first thought is you know that &iovec_arrary[9].len (offset 0x98) should point to values that make sense for a wait_queue_head struct. i'm working on understanding this better, though.
don't you guys think that 0xDEADBEEFs should go away before this so-called poc start working? any ideas on that one?
GoofMan69 said:
don't you guys think that 0xDEADBEEFs should go away before this so-called poc start working? any ideas on that one?
Click to expand...
Click to collapse
that's where the use after free bug should come in.
Code:
ioctl(binder_fd, BINDER_THREAD_EXIT, NULL);
when this is called, the binder_thread structure is freed in the kernel.
immediately after the parent process calls,
Code:
b = writev(pipefd[1], iovec_array, IOVEC_ARRAY_SZ);
in the kernel, memory is allocated to copy over iovec_array from userspace. this poc depends on the pointer from this allocation, to be the same as the recently freed binder_thread memory.
then, when the child process exits, the EPOLL cleanup will use the waitqueue in the binder_thread structure, that has been overwritten with the values in iovec_array. when EPOLL cleanup unlinks the waitqueue, 0xDEADBEEF will get overwritten by a pointer in kernelspace. this has to happen just before the writev call in the parent process starts to copy over the second buffer, which gets us a kernel space memory leak.
if writev is returning 0x1000 it means the timing is off, the wait queue offset is off, the kmalloc allocation in the writev function isn't the same as the freed binder_thread, or your kernel isn't vulnerable.
One simplifying issue is that with Kernel 3.18, we don't have KASLR, so we don't need to leak the kernel address. Hence the first part of the poc is unnecessary, assuming we can get the addresses.
Are there any rooted LGV20 variants using the 3.18 kernel? If so, it might help if someone with one of these were to post a copy of /proc/kallsyms
try
lg q710 kernel 3.18
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
chompie1337, thank you for such detailed description.
So, child must exit and epoll-cleanup code should be done to the time when parent's writev() starts to copy 2nd buffer (as you say, 0xdeadbeef will be replaced by that time). But there's a sleep(2) in the child. Do you think it is appropriate? Hardly it'll take writev 2s to copy first buffer, maybe 2ms or smth?
Also, why does child call epoll_ctl(EPOLL_CTL_DEL)? Isn't it a thing, that we should NOT do for the bug to come in?
From reading the poc, it looks like deleting the event from the epoll queue, after the binder thread has terminated, (somehow) causes the pointer wq->task_list->prev to have the value &(wq->task_list->next). If the kernel allocates its copy of the iovec array in the same place as the old binder_thread structure was, the wq->task_list->prev pointer will fall in an iov_base location in the array, and hence an iov_base will get overwritten. Moreover, the poc ensures this happens AFTER the kernel has checked that the iovec is one the user has permission to use for reading or writing. In the clobber function, then, the epoll event deletion makes the iov_base point to a position in the kernel heap--indeed, inside the kernel's pre-checked copy of the iovec array--which the poc leverages to write data to any location the kernel has access to (by first rewriting the next little bit of the pre-checked iovec array).
Unfortunately, with the 3.18 kernel, the event deletion causes a value to be written to an iov_len location in the iovec array, which allows one to change the amount of data being written but not the location being written to. This is good enough for crashing the device and probably for leaking a lot of data, but I have not been able to figure out how to use it for rooting.
If the kernel could be manipulated to allocate its copy of the iovec array 8-bytes further down in the heap, that would solve the problem, but I don't know if it can be done: I don't think the kmalloc-512 allocator will do that. But I could be wrong. Otherwise, I think one needs some other technique than the readv/writev trick used in the poc.
I am, unfortunately, quite new to this kind of thing. An experienced kernel hacker can probably see in an instant what to do.
I'm not sure the PoC crash is entirely because of the kernel version. My device (not the V20, just here to cooperate to develop the exploit) has kernel version 4.4 but it crashes at the first EPOLL_CTL_DEL. Where does the V20 crash when you change the WAITQUEUE_OFFSET?
Oh, I see... So writev would block after writing first dummy_page_4g_aligned of length 0x1000, because pipe's queue is full (pipe size is also 0x1000). So there isn't actually any timing tweak required, right?
Btw, i've managed to get some memory from kernel (from my device, not the V20) and non-null curent ptr, but kernel_read fails, even when reading 4 bytes from cur_ptr without any offset
Can anyone comment on line 119:
current_ptr = *(unsigned long *)(page_buffer + 0xe8);
What is 0xE8? Where does it come from?
Another strange thing: if i run poc with wd offset like for ex. 0xb0 right after reboot - i get another reboot right away, repeatability 100%. but if i run at first with offset like 0xc0 - of course i get writev 0x1000 and poc exits, but if i rerun poc with 0xb0 right after that - it will not cause reboot, but correct leak of mem happens
GoofMan69 said:
Oh, I see... So writev would block after writing first dummy_page_4g_aligned of length 0x1000, because pipe's queue is full (pipe size is also 0x1000). So there isn't actually any timing tweak required, right?
Click to expand...
Click to collapse
The sleep(2) is needed to make sure the THREAD_EXIT, which frees the binder_thread object, as well as the subsequent allocation of the iovec buffer in kernel memory take effect before the EPOLL_CTL_DEL. The pipe blocking happens only after the the EPOLL_CTL_DEL.
Can anyone comment on line 119:
current_ptr = *(unsigned long *)(page_buffer + 0xe8);
What is 0xE8? Where does it come from?
Click to expand...
Click to collapse
I'm guessing that 0xe8 comes from the author's looking at a hexdump of the page to find where there is a pointer to kernel stuff to help figure out where the address limit is held in memory, so it can be clobbered.
GoofMan69 said:
Oh, I see... So writev would block after writing first dummy_page_4g_aligned of length 0x1000, because pipe's queue is full (pipe size is also 0x1000). So there isn't actually any timing tweak required, right?
Btw, i've managed to get some memory from kernel (from my device, not the V20) and non-null curent ptr, but kernel_read fails, even when reading 4 bytes from cur_ptr without any offset
Can anyone comment on line 119:
current_ptr = *(unsigned long *)(page_buffer + 0xe8);
What is 0xE8? Where does it come from?
Another strange thing: if i run poc with wd offset like for ex. 0xb0 right after reboot - i get another reboot right away, repeatability 100%. but if i run at first with offset like 0xc0 - of course i get writev 0x1000 and poc exits, but if i rerun poc with 0xb0 right after that - it will not cause reboot, but correct leak of mem happens
Click to expand...
Click to collapse
page_buffer + 0xe8 should point to the current thread's thread_info structure, where the addr_limit is held
---------- Post added at 08:35 AM ---------- Previous post was at 08:19 AM ----------
arpruss said:
From reading the poc, it looks like deleting the event from the epoll queue, after the binder thread has terminated, (somehow) causes the pointer wq->task_list->prev to have the value &(wq->task_list->next).
Click to expand...
Click to collapse
yes, you are correct. i believe it is because remove_wait_queue is called for the wait_queue_head found in the binder_thread structure which eventually results in a call to __list_del where this happens:
http://androidxref.com/kernel_3.18/xref/include/linux/list.h#87
I can now leak data on my LGV20 with the 3.18 kernel using this modified poc: https://github.com/arpruss/cve2019-2215-3.18
The key is to realize that the following happens during the after-free cleanup at least on my 3.18.71 kernel:
1. The spinlock appears receive the value 0x10001
2. The prev and next pointers in the queue head point to the queue head.
If everything works, you will have a bunch of hex data, which starts with two 8-byte pointers with equal values.
This may or may not get us closer to actually elevating privileges, but I thought I'd share it to help others.
Code:
1|elsa:/data/local/tmp $ uname -a
Linux localhost 3.18.71-perf+ #1 SMP PREEMPT Tue Jul 17 14:44:34 KST 2018 aarch64
elsa:/data/local/tmp $ ./poc98
Starting POC
PARENT: Calling WRITEV
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial page
CHILD: dummy data
CHILD: leak data
writev() returns 0x12001
CHILD: Finished write to FIFO.
PARENT: Done with leaking
00000000 a0 f8 c4 f3 c0 ff ff ff a0 f8 c4 f3 c0 ff ff ff |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
arpruss said:
I can now leak data on my LGV20 with the 3.18 kernel using this modified poc: https://github.com/arpruss/cve2019-2215-3.18
The key is to realize that the following happens during the after-free cleanup at least on my 3.18.71 kernel:
1. The spinlock appears receive the value 0x10001
2. The prev and next pointers in the queue head point to the queue head.
If everything works, you will have a bunch of hex data, which starts with two 8-byte pointers with equal values.
This may or may not get us closer to actually elevating privileges, but I thought I'd share it to help others.
Code:
1|elsa:/data/local/tmp $ uname -a
Linux localhost 3.18.71-perf+ #1 SMP PREEMPT Tue Jul 17 14:44:34 KST 2018 aarch64
elsa:/data/local/tmp $ ./poc98
Starting POC
PARENT: Calling WRITEV
CHILD: Doing EPOLL_CTL_DEL.
CHILD: Finished EPOLL_CTL_DEL.
CHILD: initial page
CHILD: dummy data
CHILD: leak data
writev() returns 0x12001
CHILD: Finished write to FIFO.
PARENT: Done with leaking
00000000 a0 f8 c4 f3 c0 ff ff ff a0 f8 c4 f3 c0 ff ff ff |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Click to expand...
Click to collapse
Nice work. Now without the spinlock issue crashing, the kernel write is failing. This is because the recvmsg implementation for the 3.18 kernel checks each address right before it's copied over to the buffer. In the writev/readv the access check for addresses are all done at once at the beginning of the call, so that's why the leaking works. Working now on trying to use readv instead of recvmsg
chompie1337 said:
Nice work. Now without the spinlock issue crashing, the kernel write is failing. This is because the recvmsg implementation for the 3.18 kernel checks each address right before it's copied over to the buffer. In the writev/readv the access check for addresses are all done at once at the beginning of the call, so that's why the leaking works. Working now on trying to use readv instead of recvmsg
Click to expand...
Click to collapse
It was tricky to get it working, but I can now write to an arbitrary kernel address using: https://github.com/arpruss/cve2019-2215-3.18/blob/master/poc98-overwrite-pipe.c
Unfortunately, one more ingredient is needed: I need the address of the thread_info structure in order to modify addr_limit. On 4.4+, this is easy, as it's part of the task_struct, which the leaked current_ptr points to. On 3.18, thread_info is at the beginning of the kernel stack. So what we need to do is to leak the kernel stack location. If you know how to do that -- e.g., extracting it in some way from the big kernel heap leak -- let me know.
Or one use some other method. For instance, one can heap spray with a bunch of struct file objects, use the big kernel heap leak to find one of the sprayed objects (e.g., one can seek to a unique random location in a sparse file, and search for that offset in the leaked kernel heap), and modify its ops pointer to point to a doctored list of ops that calls a user function. I think this should work, unless we're unlucky and the binder_thread object is not anywhere near one of the sprayed file objects.
Or else if someone has the exact same kernel on a rootable device, they could send me the output of cat /proc/kallsyms, and one could modify some syscall to call a user function.
Now that I have a big kernel heap memory leak plus arbitrary address writing it's just a matter of time before we have a full exploit, I expect.
arpruss said:
It was tricky to get it working, but I can now write to an arbitrary kernel address using: https://github.com/arpruss/cve2019-2215-3.18/blob/master/poc98-overwrite-pipe.c
Unfortunately, one more ingredient is needed: I need the address of the thread_info structure in order to modify addr_limit. On 4.4+, this is easy, as it's part of the task_struct, which the leaked current_ptr points to. On 3.18, thread_info is at the beginning of the kernel stack. So what we need to do is to leak the kernel stack location. If you know how to do that -- e.g., extracting it in some way from the big kernel heap leak -- let me know.
Or one use some other method. For instance, one can heap spray with a bunch of struct file objects, use the big kernel heap leak to find one of the sprayed objects (e.g., one can seek to a unique random location in a sparse file, and search for that offset in the leaked kernel heap), and modify its ops pointer to point to a doctored list of ops that calls a user function. I think this should work, unless we're unlucky and the binder_thread object is not anywhere near one of the sprayed file objects.
Or else if someone has the exact same kernel on a rootable device, they could send me the output of cat /proc/kallsyms, and one could modify some syscall to call a user function.
Now that I have a big kernel heap memory leak plus arbitrary address writing it's just a matter of time before we have a full exploit, I expect.
Click to expand...
Click to collapse
Amazing work! Going to try it out now. How do you know that current_ptr points to task_struct? On my Pixel (3.18 kernel) current_ptr points to thread_info. Wondering why that's different?
edit: nvm, i see now. it's in an offset of the binder_thread structure.
arpruss said:
It was tricky to get it working, but I can now write to an arbitrary kernel address using: https://github.com/arpruss/cve2019-2215-3.18/blob/master/poc98-overwrite-pipe.c
Unfortunately, one more ingredient is needed: I need the address of the thread_info structure in order to modify addr_limit. On 4.4+, this is easy, as it's part of the task_struct, which the leaked current_ptr points to. On 3.18, thread_info is at the beginning of the kernel stack. So what we need to do is to leak the kernel stack location. If you know how to do that -- e.g., extracting it in some way from the big kernel heap leak -- let me know.
Or one use some other method. For instance, one can heap spray with a bunch of struct file objects, use the big kernel heap leak to find one of the sprayed objects (e.g., one can seek to a unique random location in a sparse file, and search for that offset in the leaked kernel heap), and modify its ops pointer to point to a doctored list of ops that calls a user function. I think this should work, unless we're unlucky and the binder_thread object is not anywhere near one of the sprayed file objects.
Or else if someone has the exact same kernel on a rootable device, they could send me the output of cat /proc/kallsyms, and one could modify some syscall to call a user function.
Now that I have a big kernel heap memory leak plus arbitrary address writing it's just a matter of time before we have a full exploit, I expect.
Click to expand...
Click to collapse
Isn't thread_info pointed by the stack field of task_struct?

Categories

Resources