Index: uspace/app/bithenge/blob.c
===================================================================
--- uspace/app/bithenge/blob.c	(revision 1923501101c2755eeaf9ce6a6bc27c61f77d1329)
+++ uspace/app/bithenge/blob.c	(revision ce683ed3675ae774eea9ffc3ff666bb59a43ab1e)
@@ -174,4 +174,125 @@
 }
 
+typedef struct {
+	bithenge_blob_t base;
+	const char *buffer;
+	size_t size;
+	bool needs_free;
+} memory_blob_t;
+
+static inline memory_blob_t *memory_from_blob(bithenge_blob_t *base)
+{
+	return (memory_blob_t *)base;
+}
+
+static inline bithenge_blob_t *blob_from_memory(memory_blob_t *blob)
+{
+	return &blob->base;
+}
+
+static int memory_size(bithenge_blob_t *base, aoff64_t *size)
+{
+	memory_blob_t *blob = memory_from_blob(base);
+	*size = blob->size;
+	return EOK;
+}
+
+static int memory_read(bithenge_blob_t *base, aoff64_t offset, char *buffer,
+    aoff64_t *size)
+{
+	memory_blob_t *blob = memory_from_blob(base);
+	if (offset > blob->size)
+		return ELIMIT;
+	*size = min(*size, blob->size - offset);
+	memcpy(buffer, blob->buffer + offset, *size);
+	return EOK;
+}
+
+static int memory_destroy(bithenge_blob_t *base)
+{
+	memory_blob_t *blob = memory_from_blob(base);
+	if (blob->needs_free)
+		free(blob->buffer);
+	free(blob);
+	return EOK;
+}
+
+static const bithenge_random_access_blob_ops_t memory_ops = {
+	.size = memory_size,
+	.read = memory_read,
+	.destroy = memory_destroy,
+};
+
+/** Create a blob from data. Unlike with @a
+ * bithenge_blob_t::bithenge_new_blob_from_buffer, the data is copied into a
+ * new buffer and the original data can be changed after this call. The blob
+ * must be freed with @a bithenge_blob_t::bithenge_blob_destroy after it is
+ * used.
+ * @memberof bithenge_blob_t
+ * @param[out] out Stores the created blob.
+ * @param[in] data The data.
+ * @param len The length of the data.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_blob_from_data(bithenge_blob_t **out, const void *data,
+    size_t len)
+{
+	int rc;
+	assert(data || !len);
+
+	memory_blob_t *blob = malloc(sizeof(*blob));
+	if (!blob)
+		return ENOMEM;
+	rc = bithenge_new_random_access_blob(blob_from_memory(blob),
+	    &memory_ops);
+	if (rc != EOK) {
+		free(blob);
+		return rc;
+	}
+	char *buffer = malloc(len);
+	if (!buffer) {
+		free(blob);
+		return rc;
+	}
+	memcpy(buffer, data, len);
+	blob->buffer = buffer;
+	blob->size = len;
+	blob->needs_free = true;
+	*out = blob_from_memory(blob);
+	return EOK;
+}
+
+/** Create a blob from a buffer. The buffer must exist as long as the blob
+ * does. The blob must be freed with @a bithenge_blob_t::bithenge_blob_destroy
+ * after it is used.
+ * @memberof bithenge_blob_t
+ * @param[out] out Stores the created blob.
+ * @param[in] buffer The buffer, which must not be changed until the blob is
+ * destroyed.
+ * @param len The length of the data.
+ * @param needs_free Whether the buffer should be freed with free() when the
+ * blob is destroyed.
+ * @return EOK on success or an error code from errno.h. */
+int bithenge_new_blob_from_buffer(bithenge_blob_t **out, const void *buffer,
+    size_t len, bool needs_free)
+{
+	int rc;
+	assert(buffer || !len);
+
+	memory_blob_t *blob = malloc(sizeof(*blob));
+	if (!blob)
+		return ENOMEM;
+	rc = bithenge_new_random_access_blob(blob_from_memory(blob),
+	    &memory_ops);
+	if (rc != EOK) {
+		free(blob);
+		return rc;
+	}
+	blob->buffer = buffer;
+	blob->size = len;
+	blob->needs_free = needs_free;
+	*out = blob_from_memory(blob);
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/app/bithenge/blob.h
===================================================================
--- uspace/app/bithenge/blob.h	(revision 1923501101c2755eeaf9ce6a6bc27c61f77d1329)
+++ uspace/app/bithenge/blob.h	(revision ce683ed3675ae774eea9ffc3ff666bb59a43ab1e)
@@ -166,4 +166,10 @@
     const bithenge_sequential_blob_ops_t *ops);
 
+int bithenge_new_blob_from_data(bithenge_blob_t **out, const void *data,
+    size_t len);
+
+int bithenge_new_blob_from_buffer(bithenge_blob_t **out, const void *buffer,
+    size_t len, bool needs_free);
+
 #endif
 
Index: uspace/app/bithenge/block.c
===================================================================
--- uspace/app/bithenge/block.c	(revision 1923501101c2755eeaf9ce6a6bc27c61f77d1329)
+++ uspace/app/bithenge/block.c	(revision ce683ed3675ae774eea9ffc3ff666bb59a43ab1e)
@@ -94,5 +94,5 @@
 /** Create a blob for a block device. The blob must be freed with
  * @a bithenge_blob_t::bithenge_blob_destroy after it is used.
- * @param out[out] Place to store the blob.
+ * @param[out] out Stores the created blob.
  * @param service_id The service ID of the block device.
  * @return EOK on success or an error code from errno.h. */
@@ -131,5 +131,5 @@
 	blob->service_id = service_id;
 	blob->size = size;
-	*out = &blob->base;
+	*out = blob_from_block(blob);
 
 	return EOK;
Index: uspace/app/bithenge/test.c
===================================================================
--- uspace/app/bithenge/test.c	(revision 1923501101c2755eeaf9ce6a6bc27c61f77d1329)
+++ uspace/app/bithenge/test.c	(revision ce683ed3675ae774eea9ffc3ff666bb59a43ab1e)
@@ -63,10 +63,21 @@
 int main(int argc, char *argv[])
 {
+	bithenge_blob_t *blob;
+
 	service_id_t service_id;
 	loc_service_get_id("bd/initrd", &service_id, 0);
-
-	bithenge_blob_t *blob;
 	bithenge_new_block_blob(&blob, service_id);
 	printf("Data from block:bd/initrd: ");
+	print_blob(blob);
+	bithenge_blob_destroy(blob);
+
+	const char data[] = "'Twas brillig, and the slithy toves";
+	bithenge_new_blob_from_data(&blob, data, sizeof(data));
+	printf("Data from memory (from_data): ");
+	print_blob(blob);
+	bithenge_blob_destroy(blob);
+
+	bithenge_new_blob_from_buffer(&blob, data, sizeof(data), false);
+	printf("Data from memory (from_buffer): ");
 	print_blob(blob);
 	bithenge_blob_destroy(blob);
