Skip to content

A library for creating hook-based java agents, without dealing with bytecode

License

Notifications You must be signed in to change notification settings

ShiftLeftSecurity/bctrace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maven Central

io.shiftleft:bctrace

An extensible framework for creating production-ready java agents.

bctrace exposes a simple event-driven programming model, built around the Hook abstraction, and saves the developer from the complexity of dealing with bytecode manipulation.

Instrumentation primitives

  • Notifying events to hook listeners in the case of
    • Method just started
    • Method about to return
    • Method about to rise a Throwable
    • Call site about to be invoked
    • Call site just returned
    • Call site just raised a Throwable
  • Changing runtime data:
    • Method/call-site (about to be) passed arguments
    • Method/call-site (about to be) returned value
    • Method/call-site (about to be) thrown Throwable

Features

  • Battle tested and production-ready
  • Generic vs direct APIs (this last suited for instrumenting hot spot methods)
  • Automatic packaging of dependencies
  • Supports filtering based on class hierarchy
  • Off-heap classloading, that ensures no side effects in the target application
  • Ensures no recursive event notifications are triggered from listener code
  • Ensures no exceptions raised by listeners reach the application
  • JMX metrics
  • Extensible
    • Logging
    • Help menu

Getting started

Bootstraping a new agent project

Set the coordinates for you new agent project

export ORG_ID=org.myorganization
export ARTIFACT_ID=test-agent
export VERSION=0.0.0-SNAPSHOT

Generate the project into a new folder of the current directory by using the provided archetype:

mvn archetype:generate -B \
-DarchetypeGroupId=io.shiftleft \
-DarchetypeArtifactId=bctrace-archetype \
-DarchetypeVersion=0.0.0-SNAPSHOT \
-DgroupId=$ORG_ID \
-DartifactId=$ARTIFACT_ID \
-Dversion=$VERSION

Move to the new agent project root folder

cd $ARTIFACT_ID

And build it

mvn clean package

Project structure

The newly created agent project is a multi-module Maven project, than contains

  • /agent: The agent module.
  • /playground: Several target applications to test instrumentation.

Running the agent

Run the /playground/hello-word test application:

$ java -jar playground/hello-world/target/$ARTIFACT_ID-playground-hello-world-$VERSION.jar

Hello world!

By default, the generated agent defines two hooks:

Now, run it again, attaching the agent, and compare the results:

$ java -javaagent:agent/target/$ARTIFACT_ID-$VERSION.jar -jar playground/hello-world/target/$ARTIFACT_ID-playground-hello-world-$VERSION.jar

INFO 1554349422236 Starting bctrace agent ...
INFO 1554349422267 Created String instance: "playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar"
INFO 1554349422267 Created String instance: "playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar"
INFO 1554349422267 Created String instance: "META-INF/MANIFEST.MF"
INFO 1554349422268 Created String instance: "Manifest-Version"
INFO 1554349422268 Created String instance: "1.0"
INFO 1554349422268 Created String instance: "Archiver-Version"
INFO 1554349422268 Created String instance: "Plexus Archiver"
INFO 1554349422268 Created String instance: "Built-By"
INFO 1554349422268 Created String instance: "nacho"
INFO 1554349422268 Created String instance: "Created-By"
INFO 1554349422268 Created String instance: "Apache Maven 3.5.4"
INFO 1554349422269 Created String instance: "Build-Jdk"
INFO 1554349422269 Created String instance: "1.8.0_191"
INFO 1554349422269 Created String instance: "Main-Class"
INFO 1554349422269 Created String instance: "org.myorganization.testagent.playground.helloworld.Main"
INFO 1554349422269 Created String instance: "org/myorganization/testagent/playground/helloworld/Main"
INFO 1554349422269 Created String instance: "org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422269 Created String instance: "org/myorganization/testagent/playground/helloworld/Main"
INFO 1554349422269 Created String instance: "org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422269 Created String instance: "org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422270 Created String instance: "org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422270 Created String instance: "org/"
INFO 1554349422270 Appending "" + "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!/"
INFO 1554349422270 Appending "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!/" + "org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422270 Created String instance: "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!/org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422270 Created String instance: "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!"
INFO 1554349422270 Created String instance: "/org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422270 Appending "" + "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!"
INFO 1554349422271 Appending "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!" + "/org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422271 Created String instance: "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar!/org/myorganization/testagent/playground/helloworld/Main.class"
INFO 1554349422271 Created String instance: "org.myorganization.testagent.playground.helloworld"
INFO 1554349422271 Created String instance: "META-INF/MAVEN/"
INFO 1554349422271 Created String instance: "META-INF/MAVEN/ORG.MYORGANIZATION/"
INFO 1554349422271 Created String instance: "META-INF/MAVEN/ORG.MYORGANIZATION/TEST-AGENT-PLAYGROUND-HELLO-WORLD/"
INFO 1554349422271 Created String instance: "META-INF/MAVEN/ORG.MYORGANIZATION/TEST-AGENT-PLAYGROUND-HELLO-WORLD/POM.XML"
INFO 1554349422271 Created String instance: "META-INF/MAVEN/ORG.MYORGANIZATION/TEST-AGENT-PLAYGROUND-HELLO-WORLD/POM.PROPERTIES"
INFO 1554349422272 Created String instance: "Manifest-Version"
INFO 1554349422272 Created String instance: "1.0"
INFO 1554349422272 Created String instance: "Archiver-Version"
INFO 1554349422272 Created String instance: "Plexus Archiver"
INFO 1554349422272 Created String instance: "Built-By"
INFO 1554349422272 Created String instance: "nacho"
INFO 1554349422272 Created String instance: "Created-By"
INFO 1554349422272 Created String instance: "Apache Maven 3.5.4"
INFO 1554349422272 Created String instance: "Build-Jdk"
INFO 1554349422272 Created String instance: "1.8.0_191"
INFO 1554349422272 Created String instance: "Main-Class"
INFO 1554349422272 Created String instance: "org.myorganization.testagent.playground.helloworld.Main"
INFO 1554349422272 Created String instance: "org/myorganization/testagent/playground/helloworld"
INFO 1554349422272 Created String instance: "org/myorganization/testagent/playground/helloworld/"
INFO 1554349422273 Created String instance: "org/myorganization/testagent/playground/helloworld"
INFO 1554349422273 Created String instance: "org/myorganization/testagent/playground/helloworld/"
INFO 1554349422273 Created String instance: "org/myorganization/testagent/playground/helloworld"
INFO 1554349422273 Created String instance: "org/myorganization/testagent/playground/helloworld/"
INFO 1554349422273 Created String instance: "org.myorganization.testagent.playground.helloworld"
INFO 1554349422273 Created String instance: "file:/tmp/test-agent/playground/hello-world/target/test-agent-playground-hello-world-0.0.0-SNAPSHOT.jar"
INFO 1554349422274 Appending "" + "Hello "
INFO 1554349422274 Appending "Hello " + "world"
INFO 1554349422274 Appending "Hello world" + "!"
INFO 1554349422274 Created String instance: "Hello world!"
Hello world!
INFO 1554349422274 Appending "" + ""
INFO 1554349422274 Appending "" + ".level"
INFO 1554349422275 Created String instance: ".level"  

Congratulations, your bctrace agent is up and running (and ready to grow)!

Next steps

Explore the agent documentation

Main stack

This module could not be possible without:

Authors

License

Based on brutusin:instrumentation by Ignacio del Valle Alles distributed under Apache v2.0 license.

Creating a release

VERSION="0.0.1"
mvn versions:set -DnewVersion=$VERSION
mvn versions:commit
git add pom.xml */pom.xml
git commit -m "updating version to $VERSION"
git tag v$VERSION
mvn clean test javadoc:jar deploy
git push origin v$VERSION