pylerSM / NoDeviceCheck

[Xposed module] Disable device compatibility check
http://repo.xposed.info/module/com.pyler.nodevicecheck
BSD 2-Clause "Simplified" License
82 stars 34 forks source link

Xposed presence #3

Open pylerSM opened 9 years ago

pylerSM commented 9 years ago

Need to know whether Xposed has any impact on "success/fail" state. If yes, we can hide it.

chenxiaolong commented 8 years ago

@gamer765 On my device, snet.jar exactly matches snet.dex. I disassembled the oat file with https://github.com/testwhat/SmaliEx as well as the snet.jar file and they result in the exact same smali code.

gamer765 commented 8 years ago

yeah and play services is calling snet.dex by reflection

d8ahazard commented 8 years ago

This is awesome! Currently, I'm on vacation in Florida for the next week. But when I get home, I definitely want to chat with you on Hangouts, I think maybe if they you if you and I put our heads together, we can crack this thing quite quickly. On Apr 3, 2016 7:49 PM, "gamer765" notifications@github.com wrote:

yeah and play services is calling snet.dex by reflection

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/pylerSM/NoDeviceCheck/issues/3#issuecomment-205078639

Devo7v commented 8 years ago

@d8ahazard , @gamer765 : Any luck?

Maxr1998 commented 8 years ago

I just had a totally different idea: instead of patching around the snet.jar and .dex until we hide everything they try to find, wouldn't it just be possible to replace the dex with our own version which doesn't check at all and passes all requests?

Entropy512 commented 8 years ago

No, because it's possible for the device to send attestation data to a remote server to be verified (there was a good analysis of SafetyNet that found this aspect of it). That attestation data isn't a "pass/fail" - it's information the server uses to determine a pass/fail scenario.

See Android Pay. Patching local pass/fail tests doesn't work (proven by early attempts at NoDeviceCheck), because I'm 90% sure Pay sends attestation data to the server - which fails its checks on that data. So you can't just patch a yes/no result, you need to fake information such that an attestation looks "good" to a remote server.

Maxr1998 commented 8 years ago

But would it be possible to capture the tcp packages of a device that passed SafetyNet, and then use that data to replace parts of the sent data?

marzika commented 8 years ago

The whole data sent is hashed and signed you cannot extract parts of it. Secondly, we (devs of Snapprefs) were able to replace a failing attestation with a previously accepted one, however the whole attestation expired after a while. It was back in November, haven't looked into it since then.

Entropy512 commented 8 years ago

Interesting... Do you happen to have any examples of what you did there?

It would be interesting to see just what data is in the attestation, since that would hint at SNet is looking for to build that dataset.

nayanbhana commented 8 years ago

@entropy512 I think I have some of it. I will look for it today

Entropy512 commented 8 years ago

As to the attestation expiring, from https://developers.google.com/android/reference/com/google/android/gms/safetynet/SafetyNetApi#public-methods

"When you request a compatibility check, you must provide a nonce, which is a random token generated in a cryptographically secure manner. You can obtain a nonce by generating one within your app each time you make a compatibility check request. As a more secure option, you can obtain a nonce from your own server, using a secure connection."

A server-verified attestation will likely expire after one use if the service is designed correctly - it will use a different nonce with every attestation.

Entropy512 commented 8 years ago

BTW, a potential method for hiding Xposed, based on the positive results someone had with "systemless xposed"

If I recall correctly (It's been a while, I'm rusty), Xposed keeps a backup of the "original" app_process in /system/bin - that backup's presence is likely one of the triggers of a failure.

The second thing is that SafetyNet likely checks aspects of the app_process binary (size, modification time, etc.) - Hooking anything that tries to check the file properties of app_processed and making the file appear to be the same size/modification time as stock app_process might cloak Xposed from Android Pay.

Entropy512 commented 8 years ago

@gamer765 The fact that file managers are reporting the correct number of files and you're seeing the "cloaked" files in a file manager with blank names is an indication you haven't fully cloaked the files.

If I'm reading your code correctly, I think that arraySize will always be the number of files in the original result - you are going to have blank strings in the result. I'm about to make a few comments on your github commit.

nayanbhana commented 8 years ago

@Entropy512 So it has been a while since I looked at this but I think the hash @marzika is referring to is Protocol Buffers. https://developers.google.com/protocol-buffers/

For Snapchat we used to generate our own protobuf and the server would return an attestation, the format I used there can be seen here. https://i.gyazo.com/f4fee815c2ca5b5c70940f135a983e79.png

The attestation we generated would always return a fail but at the time Snapchat wouldn't block your login. I think it was about November when Snapchat started blocking the login and I haven't looked at it since.

Entropy512 commented 8 years ago

Hmm. Perhaps Snapchat was initially ignoring the nonce when you did the replay attack?

Seems like not much information there, unless unknownData is a multi-byte affair?

Do attestations which usually "pass" contain any suexec submessages, or does presence of one of the suexec submessages (the "repeated suexec" line in dataContainer) always cause a failure in your experience?

Did you notice any patterns to the unknownData bools?

What was the typical value of the droidGuard string?

Edit: I was really expecting the attestation to include a hell of a lot more information than that...

nayanbhana commented 8 years ago

droidGuard string Cgbp9kfDzmHYAQE4YRoWCJDI_r3______wEQuJTS-vr_____AaoBFgi8u_-0_f____8BEJ7mkq_6_____wHoAa-Zm7P4_____wHoAbqB_d4FOGs4SxL8CZJhg1mxAi2L1xGeKr-lp028We0xQzTGEBz3tNVEZYMaTZ1APVFk6iiRbcj45WlYaYu38C7M_dnU3BnLA8-IRFucCGJg7zjK4CxRA8bIA2xILFfa8Nt0493ZazjpKS_Onqs6W9nrx9DxG3SdcErWiYuYbFq_VRgLF-VLUBcvr7LlzJZ4ah8Qqo3i9LrBI5MUigZkrYsZgJTE5K5Sst11m0xITkeg8R77IJFotTiQxPQopD2Fyxja96Die5DosiW_2uVCkJ5ms2dpLi6F6QTmwmL62WW_wS1SXE836B1bTXSKeNu3yyJDAK3OOsLpriMMHRvqdeCWCJ4A-oG5JPC0U8-OlrizRB_iqcpVv-x4GbS2Y3gOUZJrKl56mKYxe3YxMVMjKDAHWTIoyEIXB_vH6N5idxmpXn82IJbCtERVxwuX7WEQMewxsGaWwLyqrbMGXmoIMNzrdQULyd-BU-mkQV8uzSOO3wuer24eCFGVDuCBqvhMkeCeezwcn0t_KyQw5r2JGRvZJ49abqs38cI7g6UI-kVFQsho8DL1k0nITBM_DqfxJVUUBbuek_LwRMsy5JJiudy3J0n7xSW351mnP0WTb9eeshxKgjwT2wxE9xNSRF92LdaV7ZsGHhI5PP83erN9niQ1aBvlEGzU4dGVlMG10p6UXpJj2V88-0Wk3r_Hk3ZCLgtj1Q0BO1Wrjpc1WerqaH2kSXFPH7WGFMtfBcpovmFm1JMho-LiwNiKUPFi8Tkj69Gr3pp0CUrCdIb_HUkWDEJdLFJ8PgjRS7twnAN8f8I7qufxj2aEEQfDxsKL5l9GxoD4bM6Q6iP-gzmlvILLA0sJgCQr1u2ytjAnJnBLBxxGo8KgGIRKMs1NJnZwAc71Ur9TCo3KzNPCe-g98Y6noF_CxZhFWgJDnfHyMSDUeZv1vr6h_ogxJEaRPEn-4OZlxekJ5rUZV8JS_G-IpA7QXWv2KZw20Y4uS_qofqv7ogH-xa7UZXbRoY_H3nAA_q4id_HoUMUepJ0KICOx6Xc_R0tV_kjzxQ1ECiFWgUjrxieU6Z3fSES2wFGcHaRUdWKnS1PxprMq_IEbSQrbvAZvh5LS5HyIcAlGeOfv1GuQt2wtk-DZWgDdr-TnZzZBsAwhfu82BI1Y2P8RrtuV0IdEjlj4p382oluC7o3UOd10CiXVdxocjff7kC_TDEfxcWJGQFnQih5zHoxwUeyjaiS1bMwCZtlzaX7xyfgDTx-QtoxeViHG8CSKhs5Y2ZZYaLK1Q6eC_RbUMwjl0_vGJnTFgDO4Zz42GiWh7oyzYNtHGXp3jTYy9w5YQg6U0_w65TthAH4mXACvoqiQEhCt_uI5jqbhg0pCktxbfc78RfCS6BPD9XJL6f54ig95PnVR-3PSEqihMdJ_rVaK-l5-wr8QdHu5prgWDHlSPSUNXnBC-BuBCgBrXA6BjU8KmHP3bQujbrycVU5Ko1kzeLg46_pbOZ2EecelnyUMfMpPoHx7ax9Sfp7d2-T_WjPcfCB10ZIwFB8102To3UNFDPrwpxH9fslWb6PuY1VuAQ1VW79K-xgGqdJoi418hycjgOqvqhZf_kn_QxmOzRfJbFkZW8znaXDZq7RuaBZWOkVARgy-xwh3T0v86C1QdMfCTVb0ceOMe3KElqUlLgiYfSV9gOMOrMIuZXj3idSJkQAzRvmeU-JyCjFkNvFLG0Q'

hahaopsmeow commented 8 years ago

According to "Android Security 2015 Year in Review" (google for it, it will be top PDF link).

Page 20:

It (talking about snet) also provides a way to measure the diversity of the Android ecosystem: SIC has identified ed over 175,000 unique system partitions (and over 60,000 system partitions that have more than 1,000 active devices).

It means that SafetyNet calculates hash on /system, so installing Xposed in /system will fail.

Here is more info: https://koz.io/inside-safetynet/


The only way I see is to use Systemless Xposed. But there is another problem: SafetyNet sees Xposed and it is immediate failure. It is possible from one of the following methods: http://d3adend.org/blog/?p=589 (and few more as I can count).

But, according to the some people it is possible to fix too...

Unfortunately I am very new in this topic and need some of your help to proceed:

Please, tell me:

rich0 commented 8 years ago

Seems like the two obvious approaches are the change SafetyNet so that it reports stored hashes instead of actual ones, or to change the kernel so that when SafetyNet reads /system it gets a copy of the original /system. If it is actually hashing it at the device level (and not just individual files), that would probably require storing a copy of all blocks that are modified. If it is just hashing all the files then storing backups would be fine.

This is basically just the usual rootkit / stealth virus approach. The only way Google could really bypass that is by using remote attestation backed by a TPM (which I believe most of the ARM chips actually support these days).

If we're going to muck around in the kernel this much a systemless approach probably makes more sense, and then we just have to store a copy of an unmodified kernel someplace and if something tries to read the kernel partition just point it at the original.

hahaopsmeow commented 8 years ago

More input for Systemless approach:

SafetyNet will detect the current running app_process (zygote), so even if Xposed is installed systemless, it can still detect you're using a heavily modified binary.

Any ideas?


It seems that: systemless xposed with "detection" fix and we are good to go!

rich0 commented 8 years ago

SafetyNet will detect the current running app_process (zygote), so even if Xposed is installed systemless, it can still detect you're using a heavily modified binary.

Any ideas?

Seems like just another reason to patch the kernel. SafetyNet only knows what the kernel does it.

Again, Google can escalate that one further by planting their checks in the firmware with TPM support. Ultimately whoever controls the hardware owns the device.

marzika commented 8 years ago

Another way to detect the framework without detecting the files directly: https://github.com/rovo89/XposedInstaller/issues/93

Also, you might have noticed that when using Xposed Android Studio throws up bunch of "Warning: linker: app_process has text relocations. This is wasting memory and is a security risk." which should be theoretically solved by using -fPIC when compiling. It can also be used to detect the modified app_process.

Entropy512 commented 8 years ago

@nayanbhana Thanks. I think the droidGuard string is key here. Need to figure out how that's being built - that name is something that can't be obfuscated so that's probably a good starting point in looking through decompiled source

@hahaopsmeow There's no way it's hashing all of /system - that would take too long. It appears to be collecting file lists, and doing a "deeper" inspection of some sort on select files.

Entropy512 commented 8 years ago

Systemless xposed uses bind-mounting - so when it's "active", /system/bin/app_process is the "modified" one.

hahaopsmeow commented 8 years ago

@Entropy512 you are right. Whole system hashing makes no sense.

system_partition_files Collects various information about a configurable list of files of interest under /system. Information includes all permissions, names of files, symlink targets, selinux security context, hashes etc. Currently the list of files of interest seems empty. It is interesting that the framework makes use of red herring in order to confuse attackers: along with the files of interest, a configurable number of random files can be accessed in the same way. Great stuff, red herring approaches are commonly used in advanced app protection products. However this is not enabled by default.

More info that proves it:

How is the /system hash created? SafetyNet runs an process that recursively walks "/system" and calculates a HashTree over its contents. For every file it encounters it captures meta-information (timestamps, permissions, selinux context etc) and its SHA256 hash into a local data store. For every directory, it generates a hash that considers the store entry of every file inside the directory. If there are hash mismatches between previous and current recursive walks over /system, the offending files are entered in separate lists to be audited.

The LOG SYSTEM PARTITION FILES module continues to include the results of the SystemPartitionFileFinder sub-module. As a reminder, this module retrieves the status of various files in /system. The list of "files of interest" is configured over the air. Currently, the following files are checked, along with 5 random files:

  /system/app/providerdown.apk,
  /system/priv-app/cameraupdate.apk, 
  /system/app/cameraupdate.apk,
  /system/priv-app/ThemeManags.apk,
  /system/app/HTMLViewer.apk,
  /system/app/com.android.hardware.ext0.apk,
  /system/app/com.android.wp.net.log.apk,
  /system/app/com.google.fk.json.slo.apk,
  /system/app/com.google.model.mi.apk,
  /system/app/SettingProvider.apk,
  /system/app/SecurityCertificate.apk,
  /system/app/LiveWallpaper.apk,
  /system/app/BatteryControl.apk,
  /system/app/Models.apk,
  /system/bin/.daemon,
  /system/bin/.daemon/mis,
  /system/bin/.daemon/nis,
  /system/bin/daemonnis,
  /system/bin/nis,
  /system/bin/.sr/nis,
  /system/bin/.sr,
  /system/bin/.memnut,
  /system/bin/.suv,
  /system/bin/.sc/mis,
  /system/bin/uis,
  /system/usr/.suv,
  /system/xbin/.memnut,
  /system/xbin/.suv,
  /system/xbin/ku.sud,
  /system/xbin/.rt_daemon,
  /system/xbin/.rt_bridge,
  /system/xbin/.monkey.base,
  /system/xbin/.ext.base,
  /system/xbin/.like.base,
  /system/xbin/.look.base,
  /system/xbin/.must.base,
  /system/xbin/.team.base,
  /system/xbin/.type.base,
  /system/xbin/.view.base,
  /system/xbin/.word.base,
  /system/xbin/.zip.base,
  /system/xbin/.bat.base,
  /system/xbin/com.android.wp.net.log,
  /system/xbin/.b,
  /system/xbin/.df,
  /system/xbin/.c,
  /system/xbin/.sys.apk,
  /system/xbin/.ld.js,
  /system/xbin/.ls

Some people reported that having systemless root and systemless xposed installed but disabled allows them to use Google Pay.

So, it seems that xposed detection in snet is the key.


Guys, where do you get snet sources?

hahaopsmeow commented 8 years ago

@rich0

Seems like just another reason to patch the kernel. SafetyNet only knows what the kernel does it.

What exactly should be patched?

I think I we have sources of snet, it will be easier to understand work need to be done.

Entropy512 commented 8 years ago

I think @gamer765 was on the right track - but at least unless he tried something he didn't push to his github repo, his method for cloaking files would've left evidence in the form of "blank" files at best. With some changes, it might do the trick.

Except that in addition to hiding xposed's "backup" files, when SNet tries to probe app_process, that probe should somehow be redirected to the original app_process (e.g. SNet only sees the unmodified binary).

As to snet sources - decompiler. I believe much of the attestation is assembled elsewhere though, last time I looked through them I couldn't find where it was being assembled - however that droidGuard string helps a lot. The snet sources do reference a "droidguardResults" string... hmmm

Entropy512 commented 8 years ago

Actually, I think the DroidGuard service is somewhere buried in GMS, not in the snet package.

Entropy512 commented 8 years ago

mergeFrom in com/google/security/cryptauth/lib/risk/StarguardData.java looks interesting

pylerSM commented 8 years ago

Which API it uses to scan "/system/bin/app_processXX"? we could hook it, check for this path and redirect it to "/system/bin/app_processXX.orig" (original untouched file)

hahaopsmeow commented 8 years ago

Which API it uses to scan "/system/bin/app_processXX"? we could hook it, check for this path and redirect it to "/system/bin/app_processXX.orig" (original untouched file)

This won't work, because snet also detects where xposed is running or not. Please see below for details:

Please check it out (description of systemless xposed): http://forum.xda-developers.com/showpost.php?p=67074423

It says:

_Benefits_ OTA:

  • The system partition will not be modified or mount r/w, thus your Android devices are capable of applying OTA updates.

Android Pay:

  • Unfortunately, Android Pay won't work with Xposed enabled even if no system files are touched.
  • However, by simply toggle the disable toggle in Xposed Installer App, systemless method gives us the ability to re-gain Android Pay just in a reboot!!
  • Disabling system installed Xposed will not pass Android Pay check! Confirmed with my HTC 10 and Nexus 9.
  • Systemless Xposed is required for Xposed to live with Android Pay. Disabling won't trigger ART cache rebuild.

So, for me it seems that we need to hide from snet the fact that xposed is running.

I am about to test it now.

Entropy512 commented 8 years ago

I'm fairly certain it's not detecting that xposed is running, it's detecting that app_process changed.

I suggest reading http://unix.stackexchange.com/questions/198590/what-is-a-bind-mount - specifically, "Unlike a hard link or symbolic link, a bind mount doesn't affect what is stored on the filesystem. It's a property of the live system."

This is how systemless xposed works - the modified (xposed) app_process is NEVER written to the system partition (which is why the claim that the system partition is not modified or mounted RW).

HOWEVER - when "enabled" - systemless xposed bind-mounts a modified app_process binary at the location of the "original" app_process binary. So while the /system partition was never modified, to any application it appears that this is the case when the bindmount is enabled (Xposed active).

@pylerSM I think that is exactly (along with cleaning up @gamer765 's directory listing code a bit) needs to happen. Unfortunately I don't have time for a while to try hacking this myself, but I can read code and make some suggestions/ask questions based on what I see. :)

BTW, if I'm reading things correctly, the DroidGuard string may be serialized protobuf data - see https://github.com/google/protobuf/blob/master/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java and mergeFrom in com/google/security/cryptauth/lib/risk/StarguardData.java within the snet sources (warning: my snet sources are VERY old, generated by decompiling one of the first known snet packages)

Entropy512 commented 8 years ago

I think instead, it's probably easier to look at buildHashTree() in com/google/android/snet/Filefinder.java within the SystemPartitionFileFinder() class

I'm fairly certain this is, among other things, hashing directory listings - which is why masking a file on access but not hiding it from the directory listings fails.

hahaopsmeow commented 8 years ago

@Entropy512 great input!

Just for reference here other methods do detect xposed: http://d3adend.org/blog/?p=589

Entropy512 commented 8 years ago

Yeah - I'm fairly certain that's not being used yet.

I'm 90% certain that what is happening when systemless xposed is active is that SystemPartitionFileFinder sees a modified app_process binary.

What I can't figure out is why some people were saying that Nexus devices running AOSP-derivative firmware were having success with Android Pay in the past few months... The chances of someone's build system generating an IDENTICAL app_process binary are slim to none...

chenxiaolong commented 8 years ago

This may be a dumb brute force solution, but instead of hooking snet, couldn't we create an app_process wrapper that would chroot into a mounted Nexus system image whenever the UID of the process is known to be snet? Sure, it would be a waste of storage space, but could it work at least as a temporary solution?

For example, something like:

#define SYSTEM_IMAGE_PATH   "/storage/XXXX-XXXX/system.img.ext4"
#define SYSTEM_MOUNT_POINT  "/data/local/tmp/system"

mkdir(SYSTEM_MOUNT_POINT, 0755);
mount(SYSTEM_IMAGE_PATH, SYSTEM_MOUNT_POINT, "ext4", MS_RDONLY, "");
chroot(SYSTEM_MOUNT_POINT);
...
execv("/system/bin/app_process", argv);

EDIT: Well, chroot wouldn't work. Creating a new mount namespace and mounting the image directly to /system would be better.

hahaopsmeow commented 8 years ago

@Entropy512 Could we verify your idea somehow?

We need get latest snet sources and check how they actually do see Xposed installed. (I could try to do it, but I don't know yet how to get sources)

I have Nexus 5X and Nexus 6P for testing and I am ready to test.

Just for reference: Substrate - hooking C on Android - https://koz.io/android-substrate-c-hooking/

hahaopsmeow commented 8 years ago

Still cannot see any snet sources on Android.

Could it be that architecture of whole snet has changed?

But I see that Android loads APK from here: https://www.gstatic.com/droidguard/C4C74D1D1373D60A118D28109D7FFAECA7A892F4

There is *.so file inside the APK.

hahaopsmeow commented 8 years ago

FYI: https://github.com/pylerSM/NoDeviceCheck/issues/3#issuecomment-205074242

This doesn't exists anymore. I also checked Google Play services_v8.7.03 (2645110-238)_apkpure.com.apk it also doesn't have strings as shown on screenshots.

d8ahazard commented 8 years ago

Here's the .smali of the decompiled apk listed from the gstatic link:

http://pastebin.com/YbxBJ3Xj

hahaopsmeow commented 8 years ago

@d8ahazard It is just a wrapper for native code calls. All native code is in *.so file which is hardly obfuscated. I have absolutely no idea what it does but I bet it is some kind of smart checks...

pylerSM commented 8 years ago

Can you guys check this? Maybe you would have more ideas, since NDK hacking is new for me :D I just got idea but I havent been successful yet.

https://github.com/devadvance/rootcloak/issues/62

Wetzel402 commented 8 years ago

I apologize if I am over simplifying things...

Would it be possible to intercept the JSON response, modify ctsProfileMatch to true, then pass the response on to the requesting app? Targeting the response rather than the request?

See "Read the compatibility check response": https://developer.android.com/training/safetynet/index.html

Entropy512 commented 8 years ago

That's what NoDeviceCheck currently does.

Doesn't work with any app that verifies the attestation server-side... Which seems to be all of them that use SafetyNet at this point. (Snapchat, Android Pay)

hahaopsmeow commented 8 years ago

So, guys... Here is what I tried so far...

I took systemless xposed and replaces app_process files with untouched (original) app_process files from stock ROM. Then flashed patched zip. SNET - PASS.

Then I added some zero bytes to the end of original app_process files and flashed it again. SNET - PASS.

So, it seems that SNET doesn't check where app_process:

For me it seems it checks something else in app_process.

Any ideas what else could be checked in app_process?

pylerSM commented 8 years ago

just anything what can point on Xposed. even app_usage has info about Xposed.

https://github.com/rovo89/Xposed/blob/master/app_main2.cpp#L38

If you have AOSP sources, you can modify app_process randomly to see what could change SNET from success to fail.

Wetzel402 commented 8 years ago

Based on the discussion I had misinterpreted the way No Device Check functions.

I take it no one has been able to intercept the server response to modify isValidSignature to true? I may be over simplifying again..

stirante commented 8 years ago

What If we could use this https://github.com/evilsocket/arminject to hook open method in google play services and if it requests app_process point it to app_process.orig? It would work on native level, so application calls and native calls would be changed.

pylerSM commented 8 years ago

Does anybody have simple app which uses SafeNety checks the way Android Pay use?

What-Zit-Tooya commented 8 years ago

@pylerSM Netmarble games detect xposed in android. Here for details https://github.com/SudoCode755/SudoHide/issues/1

Entropy512 commented 8 years ago

I think fundamentally there is no way to have a "simple" app for something that matches how we believe Android Pay and Snapchat - since you need SOMETHING doing a server-side attestation check, which means an app that uses some sort of service you control.