Login Register






The stories and information posted here are artistic works of fiction and falsehood. Only a fool would take anything posted here as fact.
Thread Rating:
  • 0 Vote(s) - 0 Average


[HC Official] JWScan - Scanner and Dumper for Jar to EXE Converter filter_list
Author
Message
[HC Official] JWScan - Scanner and Dumper for Jar to EXE Converter #1
jwscan is a reverse engineering tool that helps to recognize if a PE file was created by a java to exe wrapper like Launch4j, Exe4j, JSmooth, Jar2Exe and might help you recovering the jar or .class files that are embedded into the PE. I reverse engineered the resulting exe files for doing that.

For doing that it looks after certain signatures, like the .class file magic number, PKZIP magic number and signatures that are typical for the jar to exe wrappers mentioned above and it looks for calls to java.exe or javaw.exe.
If an embedded jar or .class file is not encrypted, it will tell you the offset to it, so you know where to dump it.
The scanner also has the ability to dump the relevant part at the specified offset.


Download:


https://github.com/Doubleendedqueue/Pape...scanhc.zip


Supported OS:


Platform independend. Tested on Linux and Windows 7.

Usage:
Code:
Usage: java -jar jwscan.jar [-d <hexoffset>] <PEfile>

Option -d will dump the file at the specified offset. Just put in the offset you get after scanning a file. I.e. a typical scan result will look like this (here with a sample exe that was created by launch4j)

[Image: z335sigt.png]

Source:

This tool builds up on my Signature Scanner here: http://www.hackcommunity.com/Thread-Scal...re-scanner

The relevant source is this (written in Scala):

Spoiler:
[
Code:
scala]
/**
* A scanner for Wrappers of Jar to Exe converters. The class provides methods for
* finding indicators about the tools used to wrap the jar, finding possible locations
* of the embedded jar file and may assist in dumping it.
*
* @author Deque
* Creates a Scanner instance that operates on the given file
* @param file the file to scan or dump from
*/
class Jar2ExeScanner(file: File) {

  private lazy val scanner = new SignatureScanner(_loadSignatures(new File("javawrapperdb")))

  /**
   * A list containing the signatures and addresses where they where found.
   */
  lazy val scanResult: List[ScanResult] = scanner._findAllEPFalseMatches(file).sortWith(_._1.name < _._1.name)

  private val description = Map("[Jar Manifest]" -> "Jar manifest (strong indication for embedded jar)",
    "[PKZIP Archive File]" -> "PZIP Magic Number (weak indication for embedded zip)",
    "[java.exe]" -> "Call to java.exe (strong indication for java wrapper)",
    "[javaw.exe]" -> "Call to javaw.exe (strong indication for java wrapper)",
    "[Jar2Exe Products]" -> "Jar2Exe.com signature",
    "[JSmooth]" -> "JSmooth signature",
    "[Launch4j]" -> "Launch4j signature",
    "[Exe4j]" -> "Exe4j signature, search in your temp folder for e4jxxxx.tmp file while application is running",
    "[CAFEBABE]" -> ".class file signature(s) found")

  def readZipEntriesAt(pos: Long): java.util.List[String] =
    _readZipEntriesAt(pos).asJava
  
  def _readZipEntriesAt(pos: Long): List[String] = {
    val raf = new RandomAccessFile(file, "r")
    val is = Channels.newInputStream(raf.getChannel().position(pos))
    val zis = new ZipInputStream(is)
    var entries = new ListBuffer[String]()
    try {
      var e = zis.getNextEntry()
      while (e != null) {
        entries += e.getName()
        e = zis.getNextEntry()
      }
    } finally {
      zis.close();
    }
    entries.toList
  }

  /**
   * Creates a scan report based on the signatures found.
   *
   * @return scan report
   */
  def createReport(): String = {
    if (scanResult.length == 0) return "no indication for java wrapper found"

    val ep = "Entry point: 0x" + scanner.getEntryPoint(file).toHexString + "\n\n"
    var lastName = ""
    val sigs = (for ((sig, addr) <- scanResult) yield {
      var str = new StringBuilder()
      if (lastName != sig.name) {
        str ++= "\t* " + description.getOrElse(sig.name, sig.name) + "\n"
      }
      lastName = sig.name
      str
    }).mkString

    val zipAddr = _getZipAddresses().map("0x" + _.toHexString)
    val classAddr = _getPossibleClassAddresses.map("0x" + _.toHexString)

    val addresses = if (scanResult.contains("[CAFEBABE]")) {
      ".class offsets: " + classAddr.mkString(", ") + "\n"
    } else if (zipAddr.length > 0) {
      "ZIP/Jar offsets: " + zipAddr.mkString(", ") + "\n"
    } else ""

    "Signatures found:\n" + sigs + "\n" + ep + addresses
  }

  /**
   * Determines the offset of the beginning of zip/jar archives within the file.
   *
   * It uses the PK ZIP magic number to determine possible addresses and starts to
   * read for entries there. If there is at least one entry found, the address is
   * returned.
   *
   * @return a list of addresses where a zip/jar with entries was found
   */
  def getZipAddresses(): java.util.List[java.lang.Long] = {
    _getZipAddresses().map(new java.lang.Long(_)).asJava
  }
  
  private def _getZipAddresses(): List[Address] = {
    val possibleAddr = getPossibleZipAddresses()
    var entryNr = 0
    possibleAddr.filter(addr =>
      if (entryNr == 0) {
        entryNr += _readZipEntriesAt(addr).length
        true
      } else {
        entryNr = entryNr - 1
        false
      })
  }

  /**
   * @return a list of addresses that might be the beginning of an embedded zip or jar
   */
  private def getPossibleZipAddresses(): List[Address] =
    for ((sig, addr) <- scanResult; if sig.name == "[PKZIP Archive File]") yield addr

  /**
   * Returns offsets of the file where the 0xCAFEBABE magic number for Java .class
   * files was found. You may try to dump these files.
   *
   * @return a list of addresses that might be the beginning of an embedded jar
   */
  def getPossibleClassAddresses(): java.util.List[java.lang.Long] =
    _getPossibleClassAddresses.map(new java.lang.Long(_)).asJava
    
  private def _getPossibleClassAddresses(): List[Address] =
    for ((sig, addr) <- scanResult; if sig.name == "[CAFEBABE]") yield addr

  /**
   * Dumps the part of PE file starting at the given address to the given
   * destination path.
   *
   * @param addr the address to start dumping the file from
   * @param dest the location to save the dump to
   */
  def dumpAt(addr: Long, dest: File): Unit = {
    val raf = new RandomAccessFile(file, "r")
    val out = new FileOutputStream(dest)
    try {
      raf.seek(addr)
      val buffer = Array.fill(1024)(0.toByte)
      var bytesRead = raf.read(buffer)
      while (bytesRead > 0) {
        out.write(buffer, 0, bytesRead)
        bytesRead = raf.read(buffer)
      }
    } finally {
      raf.close()
      out.close()
    }
  }

}

object Jar2ExeScanner {

  private val version = """version: 0.1
    |author: Deque
    |last update: 6.Feb 2014""".stripMargin
    
  private val hctitle = """
_  _ ____ ____ _  _ ____ ____ _  _ _  _ _  _ _  _ _ ___ _   _  ____ ____ _  _
|__| |__| |    |_/  |    |  | |\/| |\/| |  | |\ | |  |   \_/   |    |  | |\/|
|  | |  | |___ | \_ |___ |__| |  | |  | |__| | \| |  |    |   .|___ |__| |  |
                               jwscan by deque                               """
    
  private val title = "jwscan v0.1 -- by deque"

  private val usage = """Usage: java -jar jwscan.jar [-d <hexoffset>] <PEfile>
    """.stripMargin

  private type OptionMap = scala.collection.mutable.Map[Symbol, String]

  def main(args: Array[String]): Unit = {
    invokeCLI(args)
  }

  private def invokeCLI(args: Array[String]): Unit = {
    val options = nextOption(scala.collection.mutable.Map(), args.toList)
    println(hctitle + "\n")
    if (args.length == 0 || !options.contains('inputfile)) {
      println(usage)
    } else {
      try {
        println("scanning file ...\n")
        var file = new File(options('inputfile))
        println("file name: " + file + "\n")

        if (options.contains('version)) {
          println(version)
        }

        val scanner = new Jar2ExeScanner(file)
        println(scanner.createReport())

        if (options.contains('dump)) {
          dumpFile(options, scanner)
        }
      } catch {
        case e: FileNotFoundException => System.err.println(e.getMessage())
        case e: EOFException => System.err.println("given file is no PE file")
      }
    }
  }

  private def nextOption(map: OptionMap, list: List[String]): OptionMap = {
    list match {
      case Nil => map
      case "-d" :: value :: tail =>
        nextOption(map += ('dump -> value), tail)
      case "-v" :: tail =>
        nextOption(map += ('version -> ""), tail)
      case value :: Nil => nextOption(map += ('inputfile -> value), list.tail)
      case option :: tail =>
        println("Unknown option " + option + "\n" + usage)
        sys.exit(1)
    }
  }

  private def dumpFile(options: OptionMap, scanner: Jar2ExeScanner): Unit = {
    try {
      var dumped = new File("dumped.out")
      var hexoffset = options('dump)
      if (hexoffset.startsWith("0x")) {
        hexoffset = hexoffset.drop(2)
      }
      val addr = Integer.valueOf(hexoffset, 16)
      scanner.dumpAt(addr.toInt, dumped)
      println("successfully dumped from offset 0x" + hexoffset + " to " + dumped)
    } catch {
      case e: NumberFormatException => System.err.println("no valid offset")
    }
  }
}
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.

[Image: 2YpkRjy.png]

Reply

RE: [HC Official] JWScan - Scanner for java to exe wrapper #2
Updated to V0.2
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.

[Image: 2YpkRjy.png]

Reply

RE: [HC Official] JWScan - Scanner and Dumper for Jar to EXE Converter #3
Sweet , thanks will be downloading soon. =)

Reply

RE: [HC Official] JWScan - Scanner and Dumper for Jar to EXE Converter #4
Sweet , thanks will be downloading soon. =)

Reply







Users browsing this thread: 1 Guest(s)