Extract method raw bytes - java

How to extract method raw bytes using ASM ?
I need a map of method signatures* and raw bytes
ClassReader classReader = new ClassReader(artifact.getInputStream(jarEntry));
classReader.accept(new MethodVisitor(Opcodes.ASM9) {
#Override
public void visitEnd() {
super.visitEnd();
byte[] methodRawBytes = this.?
}
}, 0);
hacks/reflection-based answers are welcome
*Method signature in a ByteCode format like Lcom/foo/CustomClass;->methodName(Ljava/lang/String;B)V

The ASM library is not designed to provide you raw bytes. But it’s not so hard to write a dedicated class file parser for such an extraction task using the documentation of the class file format.
The bigger problem is the idea of performing a malware signature check on the method’s raw bytecode itself.
Consider the following self-contained example:
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.HexFormat;
public class BytecodeSignature {
static class Example1 extends BytecodeSignature {
void method() throws IOException {
Runtime.getRuntime().exec("/sbin/whatever", new String[0]);
}
}
static class Example2 extends BytecodeSignature {
void method() throws IOException {
System.console().printf("hello");
}
}
public static void main(String[] args) throws IOException {
String methodName = "method";
for(Class<?> c: BytecodeSignature.class.getDeclaredClasses()) {
System.out.println(c);
ByteBuffer buf;
try(InputStream is = c.getResourceAsStream(c.getName() + ".class")) {
buf = ByteBuffer.wrap(is.readAllBytes());
}
buf.position(8);
int codeCP = 0, methodNameCP = 0;
for(int cp = 1, num = buf.getChar(); cp < num; cp++) {
switch(buf.get()) {
default -> throw new IllegalStateException();
case Module, Package, Class, String, MethodType
-> buf.position(buf.position() + 2);
case FieldRef, MethodRef, IfMethodRef, NameAndType,
InvokeDynamic, ConstDynamic, Int, Float
-> buf.position(buf.position() + 4);
case Double, Long -> {buf.position(buf.position() + 8); cp++;}
case MethodHandle -> buf.position(buf.position() + 3);
case Utf8 -> {
if(lookingAt(buf, "Code")) codeCP = cp;
if(lookingAt(buf, methodName)) methodNameCP = cp;
buf.position(buf.getChar() + buf.position());
}
}
}
if(codeCP == 0 || methodNameCP == 0) continue;
buf.position(buf.position() + 6);
buf.position(buf.getChar() + buf.position()); // skip interfaces
for(int memberKind = 0; memberKind < 2; memberKind++) {
int numMembers = buf.getChar(); // memberKind: 0 fields, 1 methods
for(int m = 0; m < numMembers; m++) {
boolean targetMethod = memberKind != 0
&& buf.getChar(buf.position() + 2) == methodNameCP;
buf.position(buf.position() + 6);
int numAttr = buf.getChar();
for(int a = 0; a < numAttr; a++) {
int name = buf.getChar(), length = buf.getInt();
if(targetMethod && name == codeCP) printCode(buf);
buf.position(buf.position() + length);
}
}
}
System.out.println();
}
}
// ASCII only
private static boolean lookingAt(ByteBuffer buf, String string) {
int pos = buf.position();
int num = buf.getChar(pos);
if(num != string.length()) return false;
pos += 2;
for(int six = 0; six < num; six++, pos++)
if(buf.get(pos) != string.charAt(six)) return false;
return true;
}
private static void printCode(ByteBuffer buf) {
int offset = buf.arrayOffset() + buf.position() + 8;
int length = buf.getInt(buf.position() + 4);
System.out.println(HexFormat.ofDelimiter(" ")
.formatHex(buf.array(), offset, offset + length));
}
private static final byte Utf8 = 1, Int = 3, Float = 4, Long = 5, Double = 6,
Class = 7, String = 8, FieldRef = 9, MethodRef = 10, IfMethodRef = 11,
NameAndType = 12, MethodHandle = 15, MethodType = 16,
ConstDynamic = 17, InvokeDynamic = 18, Module = 19, Package = 20;
}
This prints
class BytecodeSignature$Example1
b8 00 12 12 18 03 bd 00 1a b6 00 1c 57 b1
class BytecodeSignature$Example2
b8 00 12 12 18 03 bd 00 1a b6 00 1c 57 b1
when compiled with Eclipse and
class BytecodeSignature$Example2
b8 00 07 12 0d 03 bd 00 0f b6 00 11 57 b1
class BytecodeSignature$Example1
b8 00 07 12 0d 03 bd 00 0f b6 00 11 57 b1
when compiled with JDK 17’s javac.
Results may vary, but it does already demonstrates that the harmless
System.console().printf("hello");
produces exactly the same bytecode as the potentially problematic
Runtime.getRuntime().exec("/sbin/whatever", new String[0]);
when compiled with the same compiler, while the identical code may produce different bytecode when compiled with a different compiler. It may also differ depending on other conditions outside the method.
The reason is that the critical aspect of these methods is not the code structure (which is identical), but which classes, members, and string constants have been used and these artifacts are not stored in the method but in the constant pool.
Decoding the sequence b8 00 12 12 18 03 bd 00 1a b6 00 1c 57 b1 yields
0 invokestatic [18] // [7] with javac
3 ldc [24] // [13] with javac
5 iconst_0
6 anewarray [26] // [15] with javac
9 invokevirtual [28] // [17] with javac
12 pop
13 return
Those differing numbers are indices into the constant pool. The indices depend on whether the constants are shared with other members, have been encountered before by the compiler, or whether the compiler has a sorting strategy for the constants.
But not on the actual value.
So you can’t tell these two methods apart by looking at the raw bytes and you can’t recognize an already known method by looking at the raw bytes (when subtle unrelated things changed).
There is no way around parsing the bytecode and incorporating the referenced constants. But the good news is, the ASM library has an API to do exactly that, decoding the instructions and the referenced constants for you…

I was curios, so I inspected the code of the ASM ClassReader class.
Obviously, the library understands the class file structure and "knows" where the actual bytecode lives.
However, it doesn't seem to expose that raw information to the caller, but only allows visiting individual bytecode instructions.
The relevant (internal) method is ClassReader.readCode. As far as I know after
final int bytecodeStartOffset = currentOffset;
final int bytecodeEndOffset = currentOffset + codeLength;
bytecodeStartOffset and bytecodeEndOffset hold the limits of the code attribute you seem to be interested in, but those (and the underlying byte[]) don't get exposed to the caller directly.
You could try to patch the method to invoke some kind new of visitRawCode method on the visitor and/or request such a feature from the project. But as it stands, that doesn't seem to be a supported feature.

Related

What are the bytes between the strings in Mifare NFC? [duplicate]

This question already has answers here:
Reading Mifare Classic returns strange characters
(2 answers)
Closed 4 years ago.
When I'm reading a Mifare classic 4k card from block to block and convert the bytes to hexadecimal and then to UTF8/ASCII I get weird characters that probably control bytes and not actual text.
Since I'm just converting the whole block directly to UTF, what should I instead do to utilize those bits in between?
Below are the readings I get and to the left the expected translated value.
If you convert the hex yourself you'll see there are strange characters between the words.
c5 42 4e 49 44 00 07 4f 4f 4f 4f 4f 4f 00 4b 42 "Åbnid" "OOOOOO" "KB"
44 44 44 20 44 44 44 44 44 00 82 4d 00 c9 31 39 "DDD DDDDD" "M" "19"
39 34 34 33 34 32 00 d0 4e 4f 39 36 36 36 35 31 "944342" "NO966651"
00000000000070f78800000000000000
30 32 32 20 20 41 53 00 d3 54 4f 54 41 4c 20 4b "022" "AS" "Total k"
4f 4e 54 52 4f 4f 4f 20 41 53 20 00 c9 30 32 38 "ONTROOO AS" "028"
37 30 34 33 33 00 c9 32 30 32 31 30 32 31 31 00 "70433" "20210211"
00000000000070f78800000000000000
How can I implement a method that takes in either a string of hex or array of bytes[] and only returns the words by comma seperation?
You can read by address, probably, you only require to read by data address.
Data Address start from 0 to 63 for Mifare Classic card, 16 sectors with 4 blocks (=1024 bytes)). But Address 0 always store UID or Manufacturer ID. So, start reading from Address 1, Address 2...Address 63. Let me break down for you,
Sector 0: Address 0 , Address 1, Address 2, Address 3
UID/ManufacturerID, Data , Data ,Sector Trail (KeyA,AccessKey,KeyB)
Sector 1: Address 4, Address 5, Address 6, Address 7
Data , Data , Data , Sector Trail
...
Sector 63 ...
So Sector Trail = 00000000000070f78800000000000000
KeyA = 000000000000
AccessKey = 70f78800
KeyB = 000000000000
So every sector, you skip the last address if you don't set read and write protection.So Try this.And Change accordingly, this could be sufficient to read
// final data
String data="";
// read sector 1 and 2
for(int sector = 1; sector < 3, sector++){
// auth sector
auth = mfc.authenticateSectorWithKeyA(sector, bytekey3);
if(auth) {
// read blocks from sector
data += convertHexToString(readBlockData(sector)).trim();
}
}
// read block
private String readBlockData(int sector) {
String blockvalues = "";
// Read all blocks in sector
for (int block = 0; (block < mfc.getBlockCountInSector(sector)); ++block) {
// Get block number for sector + block
int blockIndex = (mfc.sectorToBlock(sector) + block);
try {
// Create a string of bits from block data and fix endianness
// http://en.wikipedia.org/wiki/Endianness
if (block < 3) {
// Read block data from block index
byte[] data = mfc.readBlock(blockIndex);
if (!(sector == 0 && block == 0)) {
String temp = ByteArrayToHexString(data);
blockvalues += temp;
Log.i(TAG, "Block " + blockIndex + " : " + temp);
rawData += ("Block " + blockIndex + " : " + temp + "\n");
}
}
} catch (IOException e) {
Log.e(TAG, "Exception occurred " + e.getLocalizedMessage());
}
}
return blockvalues.trim();
}
public String convertHexToString(String hex) {
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
//49204c6f7665204a617661 split into two characters 49, 20, 4c...
for (int i = 0; i < hex.length() - 1; i += 2) {
//grab the hex in pairs
String output = hex.substring(i, (i + 2));
//convert hex to decimal
int decimal = Integer.parseInt(output, 16);
//convert the decimal to character
sb.append((char) decimal);
temp.append(decimal);
}
System.out.println("Decimal : " + temp.toString());
return sb.toString().trim();
}
private String ByteArrayToHexString(byte[] inarray) {
int i, j, in;
String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
"B", "C", "D", "E", "F"};
String out = "";
for (j = 0; j < inarray.length; ++j) {
in = inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
return out;
}
last part will be string manipulation. so basically, replay all the double quote with space and use String[]yourdata = data.split("\s+"); and you will get your data. Some of the code I borrow from this link

Changing output into 4x4 matrices

So I'm working on a method in Java that basically takes a random string of letters then goes through the method and changes the string into parity bits, which is basically converting each character to its numeric value in binary.
This is what I have:
public class ShiftData {
//this is the method that where Logic is implemented..
static String shiftRows(String text) {
//character array to store given String elements into an array..
char[] chs = text.toCharArray();
StringBuffer samBuffer = new StringBuffer();
//loop through the length of the character array..
for (int i = 0; i < chs.length; i++) {
//adding characters to the StringBuffer...
samBuffer.append(Integer.toHexString((int) chs[i]));
// here in the above statement toHexString method pads parity bit and converts to hexadecimal value..
}
return samBuffer.toString();//returning the value
}
}
This is the code that converts the string into 4x4 matrices:
if(text !=null && !text.isEmpty()) {
int len = text.length();
int rem = len %16;
int padChars = 16-rem;
for(int i =0; i < (len+padChars); i++) {
if(i < len) {
System.out.print(text.charAt(i)+ " ");
} else {
System.out.print( "A ");
}
if((i+1) % 4 == 0)
System.out.println();
if((i+1) % 16 == 0)
System.out.println("\n");
}
}
So basically if the input string is: WVOGJTXQHUHXICWYYMGHTRKQHQPWKYVGLPYSPWGOINTOFOPMO
The output should look like this:
d7 56 cf 47
d4 d8 d1 ca
48 d8 48 55
59 c9 c3 d7
59 4d 47 48
d2 4b d1 d4
50 d7 48 d1
47 4b 59 56
cc 50 59 53
d7 47 cf 50
d4 cf c9 4e
4d c6 cf 50
cf 41 41 41
41 41 41 41
41 41 41 41
41 41 41 41
I just need help combining the codes! I can get them working separately but I cant get the output I need. Please show how you would code this.
Don't use StringBuffer. Use StringBuilder instead.
Your printing loop is writing one letter at a time, separated by 3 spaces (and newlines). Letters in hex consist of two hex digits, as you already show in the desired output, so that won't work.
Your code prints blank lines at the end, which you probably don't want.
Integer.toHexString() will return a single digits if value is 0-15.
static String shiftRows(String text) {
char[] chs = text.toCharArray();
StringBuilder samBuffer = new StringBuilder();
for (int i = 0; i < chs.length; i++)
samBuffer.append(String.format("%02x", (int)chs[i])); // always 2 hex digits, even for 0-15
return samBuffer.toString();
}
public static void main(String[] args) {
String text = shiftRows("WVOGJTXQHUHXICWYYMGHTRKQHQPWKYVGLPYSPWGOINTOFOPMO");
if (text != null && ! text.isEmpty()) {
int len = (text.length() + 31) / 32 * 32; // round up to next increment of 32 (16 hex pairs)
for (int i = 0; i < len; i += 2) {
if (i != 0 && i % 8 == 0) { // every 4 hex pairs, but not first time
System.out.println();
if (i % 32 == 0) // every 16 hex pairs
System.out.println();
}
if (i < text.length())
System.out.print(text.substring(i, i + 2) + " ");
else
System.out.print("41 ");
}
}
}

arraylist in self-designed class errors. please help me

This is my Class
1 // This class reads in integers and puts the values into a set
2
3 import java.util.ArrayList;
4 import java.util.*;
5
6 class Set {
7
8 private ArrayList<Integer> members;
9 private static int quantity = 0;
10
11 // Constructors
12 public Set() {
13 new ArrayList<Integer>();
7
8 private ArrayList<Integer> members;
9 private static int quantity = 0;
10
11 // Constructors
12 public Set() {
13 new ArrayList<Integer>();
14 }
15
16 public Set(int member){
17 new ArrayList<Integer>();
18 addMember(member);
19 quantity++;
20 }
21 // Accessors
22 public static int getQuantity() {
23 return quantity;
24 }
25
26 // Mutators
27 public void addMember(int member) {
28 members.add(member);
29 }
30 // toString() method
31 public String toString() {
32 int i;
33 String str = "[";
34 System.out.print("[");
35 for(i=0; i<getQuantity(); i++){
36 str += members.get(i);
37 if(i+1 == getQuantity())
38 str += "]";
39 else
40 System.out.print(", ");
41 str += ", ";
42 }
43 return str;
44 }
45
46 // Return true if 'this' is a subset of 'set',
47 // otherwise return false.
48 public boolean isSubset(Set set) {
49 if(this.members.contains(set))
50 return true;
51 else
52 return false;
53 }
54 // Return true if 'this' is equals to 'obj',
55 // Otherwise return false
56 public boolean equals(Set set) {
57 return (members.contains(set) && set.members.contains(this));
58 }
59 }
And this is my Test case.
1 // This program reads two sets of integers A and B, and determines
2 // if A is a subset of B, and if A is same as B.
3
4 import java.util.Scanner;
5 import java.util.ArrayList;
6
7 public class TestSet {
8
9 public static void main(String[] args) {
10 Scanner sc = new Scanner(System.in);
11 int i, setAnum, setBnum;
12
13 System.out.print("Enter number of elements in set A: ");
14 setAnum = sc.nextInt();
15 ArrayList<Integer> list1 = new ArrayList<Integer>();
16
17 System.out.print("Enter elements for set A: ");
18 for(i=0; i<setAnum; i++)
19 list1.add(sc.nextInt());
20
21 Set setA = new Set();
22 for(i=0; i<setAnum; i++)
23 setA.addMember(list1.get(i));
24
25 System.out.print("Enter number of elements in set A: ");
26 setBnum = sc.nextInt();
27 ArrayList<Integer> list2 = new ArrayList<Integer>();
28
29 System.out.print("Enter elements for set A: ");
30 for(i=0; i<setBnum; i++)
31 list2.add(sc.nextInt());
32
33 Set setB = new Set();
34 for(i=0; i<setAnum; i++)
35 setB.addMember(list2.get(i));
36
37 System.out.println("Set A: " + setA);
38 System.out.println("Set B: " + setB);
39
40 if (setA.isSubset(setB)) {
41 System.out.println("Set A is a subset of set B.");
42 }
43 else {
44 System.out.println("Set A is not a subset of set B.");
45 }
46 if (setA.equals(setB))
47 System.out.println("Set A is equal to set B.");
48 else
49 System.out.println("Set A is not equal to set B.");
50 }
51
52 }
I keep getting this error
Exception in thread "main" java.lang.NullPointerException
at Set.addMember(Set.java:28)
at TestSet.main(TestSet.java:23)
I can read and pinpoint where the problem is but I don't know what to correct it to. This is the first time I'm writing a user-defined class with an ArrayList inside. Previously I've only be writing classes with primitive data types. So I'm confused with a lot of things like what the constructors accessors and mutators are supposed to look like, when to use the 'this' reference. Someone answered and I inferred that if I'm using an arraylist here with the attribute 'members', I should use the reference to 'members' rather than 'this' because that's the attribute that I want to play around with. I know it's not a hard and fast rule but I sorta get the picture. Please help!!
The constructor:
public Set() {
new ArrayList<Integer>();
}
doesn't do anything. It just creates an object, and discards it. So the members instance variable is still null. Change the constructor to:
public Set() {
members = new ArrayList<Integer>();
}
And please choose a different name for your class. Set is already an interface in Java API.

possible to read specific types from memory?

Using JNA I have figured out how to read/write to an address but I am not sure how to figure out what type of data it is for example
D0 D1 D2 D3 D4 D5 D6 D7
someProgram.exe + "0x755A523D0" : 20 00 00 00 02 00 00 00
D8 D9 DA DA DB DC DE DF
someProgram.exe + "0x755A523D8" : 14 00 00 00 04 00 00 00
I am using a third party memory viewer to find these values so that I can test results against my program.
The two address above hold 4 Integers easy to search for just scan every 4 bytes and convert it to an Integer but where it gets more tricky is if I have the following addresses
D0 D1 D2 D3 D4 D5 D6 D7
someProgram.exe + "0x755A523D0" : 20 00 00 00 02 00 00 00
D8 D9 DA DA DB DC DE DF
someProgram.exe + "0x755A523D8" : 14 00 00 00 04 00 00 00
Just to prove my point they are exactly the same as above addresses but they are not Integers they are Longs
It could also be storing 4 shorts 8 bytes or a combination of Types.
Would it be possible to detect what the value Type is and read in the correct values with JNA?
code snippet of read memory
public static int[] ReadMyProcessMemory(Pointer ProcessToReadFrom, int AdressToReadFrom, int NumberOfBytesToRead)
{
//Make the Desired Functions available
Kernel32 Kernel32dll = Kernel32.INSTANCE;
int offset = AdressToReadFrom;
IntByReference baseAddress = new IntByReference();
baseAddress.setValue(offset);
Memory outputBuffer = new Memory(NumberOfBytesToRead);
boolean reader = Kernel32dll.ReadProcessMemory(ProcessToReadFrom, offset, outputBuffer, NumberOfBytesToRead, null);
if (reader)
{
//Process the received Data
byte[] bufferBytes = outputBuffer.getByteArray(0, NumberOfBytesToRead);
//Who wants signed byte? NOONE ! Lets convert it to a nice int !
int[] realvalues = new int[bufferBytes.length];
for (int i = 0; i < bufferBytes.length; i++)
{
if (bufferBytes[i] < 0)
{
realvalues[i] = 256 + bufferBytes[i];
}
else
{
realvalues[i] = bufferBytes[i];
}
}
//Conversion done ! lets Return the data (Remember its integer not hex)
return realvalues;
}
else
{
//Reading went wrong - SHIT
return null;
}
}
public interface Kernel32 extends StdCallLibrary
{
Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
boolean ReadProcessMemory(Pointer hProcess, int inBaseAddress, Pointer outputBuffer, int nSize, IntByReference outNumberOfBytesRead);
public Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, int dwProcessId);
boolean WriteProcessMemory(Pointer hProcess, int AdressToChange, Pointer ValuesToWrite, int nSize, IntByReference irgendwas);
int GetLastError();
//Needed for some Windows 7 Versions
boolean EnumProcesses(int[] ProcessIDsOut, int size, int[] BytesReturned);
int GetProcessImageFileNameW(Pointer Process, char[] outputname, int lenght);
}
No, without further information about the types (somewhere in the memory) this is not possible

Java stripping zeros from function

I'm trying to flip some bytes around in Java and the function I have is working correctly for some bytes and failing for others.
The function I am using is this:
public static int foldInByte(int m, int pos, byte b) {
int tempInt = (b << (pos * 8));
tempInt = tempInt & (0x000000ff << (pos * 8));
m = m | tempInt;
return m;
}
And the code that implements this is:
byte[] bitMaskArray = new byte[]{
byteBuffer.get(inputIndex),
byteBuffer.get(inputIndex + 1),
byteBuffer.get(inputIndex + 2),
byteBuffer.get(inputIndex + 3)};
int tempInt = 0;
tempInt = foldInByte(0, 3, bitMaskArray[3]);
tempInt = foldInByte(tempInt, 2, bitMaskArray[2]);
tempInt = foldInByte(tempInt, 1, bitMaskArray[1]);
tempInt = foldInByte(tempInt, 0, bitMaskArray[0]);
bitMask = tempInt;
The bytes are being read from a ByteBuffer with the byteOrder being Little Endian.
For example, the bytes 00 01 B6 02 set the bitMask to: 2B60100 - which works perfectly in my program.
However, if the bytes are A0 01 30 00, the bitMask is set to: 3001A0 - which has stipped the last zero from the bitmask.
Is there any way I can stop Java from stipping off trailing zeros?
I hope that makes sense.
Thanks
Tony
The zeros are not being stripped -- both examples cited are correct.
00 01 B6 02 is the 4-byte little-endian for 2B60100
A0 01 30 00 is the 4-byte little-endian for 3001A0
The zeros are there, but probably just not being printed. The System.out.print family of calls will not print leading zero digits.
I might mention that your method is needlessly complex. Here is a single method that computes the same value:
static int extractLittleEndian4(byte[] buf, int index)
{
int a = buf[index+0]&0xff, b = buf[index+1]&0xff, c = buf[index+2]&0xff, d = buf[index+3]&0xff;
return a | (b << 8) | (c << 16) | (d << 24);
}
It looks like you have a ByteBuffer filled with your bytes already. Why don't you let the ByteBuffer reverse the bytes for you? Just add the bytes to the buffer (BIG_ENDIAN is the default if you want to add an integer instead of bytes) and then change the order before reading the integer.
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
int output = byteBuffer.getInt(0);
If all you're doing is reversing the byte order, let the library do the work for you. If you happened to start with an integer value, you can even just do this:
int input = ...;
int output = Integer.reverseBytes(input);

Categories